Merge "Use SceneTransitionLayout for weather clock" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 1233fa1..85323c3 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -159,7 +159,6 @@
 aconfig_declarations {
     name: "com.android.window.flags.window-aconfig",
     package: "com.android.window.flags",
-    container: "system",
     srcs: ["core/java/android/window/flags/*.aconfig"],
 }
 
@@ -173,7 +172,6 @@
 aconfig_declarations {
     name: "android.hardware.devicestate.feature.flags-aconfig",
     package: "android.hardware.devicestate.feature.flags",
-    container: "system",
     srcs: ["core/java/android/hardware/devicestate/feature/*.aconfig"],
 }
 
@@ -187,7 +185,6 @@
 aconfig_declarations {
     name: "com.android.hardware.input.input-aconfig",
     package: "com.android.hardware.input",
-    container: "system",
     srcs: ["core/java/android/hardware/input/*.aconfig"],
 }
 
@@ -207,7 +204,6 @@
 aconfig_declarations {
     name: "com.android.text.flags-aconfig",
     package: "com.android.text.flags",
-    container: "system",
     srcs: ["core/java/android/text/flags/*.aconfig"],
 }
 
@@ -226,7 +222,6 @@
 aconfig_declarations {
     name: "android.location.flags-aconfig",
     package: "android.location.flags",
-    container: "system",
     srcs: [
         "location/java/android/location/flags/*.aconfig",
     ],
@@ -248,7 +243,6 @@
 aconfig_declarations {
     name: "android.nfc.flags-aconfig",
     package: "android.nfc",
-    container: "system",
     srcs: ["nfc/java/android/nfc/*.aconfig"],
 }
 
@@ -279,7 +273,6 @@
 aconfig_declarations {
     name: "android.security.flags-aconfig",
     package: "android.security",
-    container: "system",
     srcs: ["core/java/android/security/*.aconfig"],
 }
 
@@ -300,7 +293,6 @@
 aconfig_declarations {
     name: "android.app.usage.flags-aconfig",
     package: "android.app.usage",
-    container: "system",
     srcs: ["core/java/android/app/usage/*.aconfig"],
 }
 
@@ -384,7 +376,6 @@
 aconfig_declarations {
     name: "android.companion.virtualdevice.flags-aconfig",
     package: "android.companion.virtualdevice.flags",
-    container: "system",
     srcs: ["core/java/android/companion/virtual/flags/*.aconfig"],
 }
 
@@ -397,7 +388,6 @@
 aconfig_declarations {
     name: "android.companion.virtual.flags-aconfig",
     package: "android.companion.virtual.flags",
-    container: "system",
     srcs: ["core/java/android/companion/virtual/*.aconfig"],
 }
 
@@ -405,7 +395,6 @@
 aconfig_declarations {
     name: "android.view.inputmethod.flags-aconfig",
     package: "android.view.inputmethod",
-    container: "system",
     srcs: ["core/java/android/view/inputmethod/flags.aconfig"],
 }
 
@@ -419,7 +408,6 @@
 aconfig_declarations {
     name: "android.os.vibrator.flags-aconfig",
     package: "android.os.vibrator",
-    container: "system",
     srcs: ["core/java/android/os/vibrator/*.aconfig"],
 }
 
@@ -433,7 +421,6 @@
 aconfig_declarations {
     name: "android.view.flags-aconfig",
     package: "android.view.flags",
-    container: "system",
     srcs: ["core/java/android/view/flags/*.aconfig"],
 }
 
@@ -452,7 +439,6 @@
 aconfig_declarations {
     name: "android.view.accessibility.flags-aconfig",
     package: "android.view.accessibility",
-    container: "system",
     srcs: ["core/java/android/view/accessibility/flags/*.aconfig"],
 }
 
@@ -471,7 +457,6 @@
 aconfig_declarations {
     name: "android.hardware.flags-aconfig",
     package: "android.hardware.flags",
-    container: "system",
     srcs: ["core/java/android/hardware/flags/*.aconfig"],
 }
 
@@ -485,7 +470,6 @@
 aconfig_declarations {
     name: "android.widget.flags-aconfig",
     package: "android.widget.flags",
-    container: "system",
     srcs: ["core/java/android/widget/flags/*.aconfig"],
 }
 
@@ -505,7 +489,6 @@
 aconfig_declarations {
     name: "android.content.pm.flags-aconfig",
     package: "android.content.pm",
-    container: "system",
     srcs: ["core/java/android/content/pm/flags.aconfig"],
 }
 
@@ -526,7 +509,6 @@
 aconfig_declarations {
     name: "android.content.res.flags-aconfig",
     package: "android.content.res",
-    container: "system",
     srcs: ["core/java/android/content/res/*.aconfig"],
 }
 
@@ -547,7 +529,6 @@
 aconfig_declarations {
     name: "com.android.media.flags.bettertogether-aconfig",
     package: "com.android.media.flags",
-    container: "system",
     srcs: ["media/java/android/media/flags/media_better_together.aconfig"],
 }
 
@@ -568,7 +549,6 @@
 aconfig_declarations {
     name: "com.android.media.flags.editing-aconfig",
     package: "com.android.media.editing.flags",
-    container: "system",
     srcs: [
         "media/java/android/media/flags/editing.aconfig",
     ],
@@ -584,7 +564,6 @@
 aconfig_declarations {
     name: "com.android.media.flags.projection-aconfig",
     package: "com.android.media.projection.flags",
-    container: "system",
     srcs: [
         "media/java/android/media/flags/projection.aconfig",
     ],
@@ -615,7 +594,6 @@
 aconfig_declarations {
     name: "android.media.tv.flags-aconfig",
     package: "android.media.tv.flags",
-    container: "system",
     srcs: ["media/java/android/media/tv/flags/media_tv.aconfig"],
 }
 
@@ -629,7 +607,6 @@
 aconfig_declarations {
     name: "android.app.ondeviceintelligence-aconfig",
     package: "android.app.ondeviceintelligence.flags",
-    container: "system",
     srcs: ["core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig"],
 }
 
@@ -643,7 +620,6 @@
 aconfig_declarations {
     name: "android.permission.flags-aconfig",
     package: "android.permission.flags",
-    container: "system",
     srcs: ["core/java/android/permission/flags.aconfig"],
 }
 
@@ -663,7 +639,6 @@
 aconfig_declarations {
     name: "android.database.sqlite-aconfig",
     package: "android.database.sqlite",
-    container: "system",
     srcs: ["core/java/android/database/sqlite/*.aconfig"],
 }
 
@@ -683,7 +658,6 @@
 aconfig_declarations {
     name: "android.hardware.biometrics.flags-aconfig",
     package: "android.hardware.biometrics",
-    container: "system",
     srcs: ["core/java/android/hardware/biometrics/flags.aconfig"],
 }
 
@@ -735,7 +709,6 @@
 aconfig_declarations {
     name: "android.multiuser.flags-aconfig",
     package: "android.multiuser",
-    container: "system",
     srcs: ["core/java/android/content/pm/multiuser.aconfig"],
 }
 
@@ -749,7 +722,6 @@
 aconfig_declarations {
     name: "android.app.flags-aconfig",
     package: "android.app",
-    container: "system",
     srcs: ["core/java/android/app/*.aconfig"],
 }
 
@@ -763,7 +735,6 @@
 aconfig_declarations {
     name: "android.hardware.radio.flags-aconfig",
     package: "android.hardware.radio",
-    container: "system",
     srcs: ["core/java/android/hardware/radio/*.aconfig"],
 }
 
@@ -777,7 +748,6 @@
 aconfig_declarations {
     name: "android.credentials.flags-aconfig",
     package: "android.credentials.flags",
-    container: "system",
     srcs: ["core/java/android/credentials/flags.aconfig"],
     exportable: true,
 }
@@ -799,7 +769,6 @@
 aconfig_declarations {
     name: "android.view.contentprotection.flags-aconfig",
     package: "android.view.contentprotection.flags",
-    container: "system",
     srcs: ["core/java/android/view/contentprotection/flags/*.aconfig"],
 }
 
@@ -813,7 +782,6 @@
 aconfig_declarations {
     name: "com.android.server.flags.services-aconfig",
     package: "com.android.server.flags",
-    container: "system",
     srcs: ["services/core/java/com/android/server/flags/*.aconfig"],
 }
 
@@ -827,7 +795,6 @@
 aconfig_declarations {
     name: "android.service.appprediction.flags-aconfig",
     package: "android.service.appprediction.flags",
-    container: "system",
     srcs: ["core/java/android/service/appprediction/flags/*.aconfig"],
 }
 
@@ -841,7 +808,6 @@
 aconfig_declarations {
     name: "android.service.controls.flags-aconfig",
     package: "android.service.controls.flags",
-    container: "system",
     srcs: ["core/java/android/service/controls/flags/*.aconfig"],
 }
 
@@ -855,7 +821,6 @@
 aconfig_declarations {
     name: "android.service.voice.flags-aconfig",
     package: "android.service.voice.flags",
-    container: "system",
     srcs: ["core/java/android/service/voice/flags/*.aconfig"],
 }
 
@@ -869,7 +834,6 @@
 aconfig_declarations {
     name: "android.service.autofill.flags-aconfig",
     package: "android.service.autofill",
-    container: "system",
     srcs: [
         "services/autofill/bugfixes.aconfig",
         "services/autofill/features.aconfig",
@@ -886,7 +850,6 @@
 aconfig_declarations {
     name: "android.companion.flags-aconfig",
     package: "android.companion",
-    container: "system",
     srcs: ["core/java/android/companion/*.aconfig"],
 }
 
@@ -900,7 +863,6 @@
 aconfig_declarations {
     name: "android.net.platform.flags-aconfig",
     package: "android.net.platform.flags",
-    container: "system",
     srcs: ["core/java/android/net/flags.aconfig"],
     visibility: [":__subpackages__"],
 }
@@ -909,7 +871,6 @@
 aconfig_declarations {
     name: "com.android.net.thread.platform.flags-aconfig",
     package: "com.android.net.thread.platform.flags",
-    container: "system",
     srcs: ["core/java/android/net/thread/flags.aconfig"],
 }
 
@@ -930,7 +891,6 @@
 aconfig_declarations {
     name: "android.media.playback.flags-aconfig",
     package: "com.android.media.playback.flags",
-    container: "system",
     srcs: ["media/jni/playback_flags.aconfig"],
 }
 
@@ -949,7 +909,6 @@
 aconfig_declarations {
     name: "android.net.vcn.flags-aconfig",
     package: "android.net.vcn",
-    container: "system",
     srcs: ["core/java/android/net/vcn/*.aconfig"],
 }
 
@@ -963,7 +922,6 @@
 aconfig_declarations {
     name: "device_policy_aconfig_flags",
     package: "android.app.admin.flags",
-    container: "system",
     srcs: [
         "core/java/android/app/admin/flags/flags.aconfig",
     ],
@@ -991,7 +949,6 @@
 aconfig_declarations {
     name: "android.service.chooser.flags-aconfig",
     package: "android.service.chooser",
-    container: "system",
     srcs: ["core/java/android/service/chooser/flags.aconfig"],
 }
 
@@ -1010,7 +967,6 @@
 aconfig_declarations {
     name: "framework-jobscheduler-job.flags-aconfig",
     package: "android.app.job",
-    container: "system",
     srcs: ["apex/jobscheduler/framework/aconfig/job.aconfig"],
 }
 
@@ -1024,7 +980,6 @@
 aconfig_declarations {
     name: "android.service.dreams.flags-aconfig",
     package: "android.service.dreams",
-    container: "system",
     srcs: ["core/java/android/service/dreams/flags.aconfig"],
 }
 
@@ -1065,7 +1020,6 @@
 aconfig_declarations {
     name: "android.app.contextualsearch.flags-aconfig",
     package: "android.app.contextualsearch.flags",
-    container: "system",
     srcs: ["core/java/android/app/contextualsearch/flags.aconfig"],
 }
 
@@ -1079,7 +1033,6 @@
 aconfig_declarations {
     name: "android.app.smartspace.flags-aconfig",
     package: "android.app.smartspace.flags",
-    container: "system",
     srcs: ["core/java/android/app/smartspace/flags.aconfig"],
 }
 
@@ -1100,7 +1053,6 @@
 aconfig_declarations {
     name: "android.view.contentcapture.flags-aconfig",
     package: "android.view.contentcapture.flags",
-    container: "system",
     srcs: ["core/java/android/view/contentcapture/flags/*.aconfig"],
 }
 
@@ -1114,7 +1066,6 @@
 aconfig_declarations {
     name: "android.hardware.usb.flags-aconfig",
     package: "android.hardware.usb.flags",
-    container: "system",
     srcs: ["core/java/android/hardware/usb/flags/*.aconfig"],
 }
 
@@ -1135,7 +1086,6 @@
 aconfig_declarations {
     name: "android.tracing.flags-aconfig",
     package: "android.tracing",
-    container: "system",
     srcs: ["core/java/android/tracing/flags.aconfig"],
 }
 
@@ -1154,7 +1104,6 @@
 aconfig_declarations {
     name: "android.appwidget.flags-aconfig",
     package: "android.appwidget.flags",
-    container: "system",
     srcs: ["core/java/android/appwidget/flags.aconfig"],
 }
 
@@ -1168,7 +1117,6 @@
 aconfig_declarations {
     name: "android.server.app.flags-aconfig",
     package: "android.server.app",
-    container: "system",
     srcs: ["services/core/java/com/android/server/app/flags.aconfig"],
 }
 
@@ -1182,7 +1130,6 @@
 aconfig_declarations {
     name: "android.webkit.flags-aconfig",
     package: "android.webkit",
-    container: "system",
     srcs: [
         "core/java/android/webkit/*.aconfig",
         "services/core/java/com/android/server/webkit/*.aconfig",
@@ -1199,7 +1146,6 @@
 aconfig_declarations {
     name: "android.provider.flags-aconfig",
     package: "android.provider",
-    container: "system",
     srcs: ["core/java/android/provider/*.aconfig"],
 }
 
@@ -1220,7 +1166,6 @@
 aconfig_declarations {
     name: "android.speech.flags-aconfig",
     package: "android.speech.flags",
-    container: "system",
     srcs: ["core/java/android/speech/flags/*.aconfig"],
 }
 
@@ -1241,7 +1186,6 @@
 aconfig_declarations {
     name: "android.content.flags-aconfig",
     package: "android.content.flags",
-    container: "system",
     srcs: ["core/java/android/content/flags/flags.aconfig"],
 }
 
@@ -1255,7 +1199,6 @@
 aconfig_declarations {
     name: "android.adaptiveauth.flags-aconfig",
     package: "android.adaptiveauth",
-    container: "system",
     srcs: ["core/java/android/adaptiveauth/*.aconfig"],
 }
 
@@ -1269,7 +1212,6 @@
 aconfig_declarations {
     name: "android.crashrecovery.flags-aconfig",
     package: "android.crashrecovery.flags",
-    container: "system",
     srcs: ["packages/CrashRecovery/aconfig/flags.aconfig"],
 }
 
@@ -1290,7 +1232,6 @@
 aconfig_declarations {
     name: "android.net.wifi.flags-aconfig",
     package: "android.net.wifi.flags",
-    container: "system",
     srcs: ["wifi/*.aconfig"],
 }
 
@@ -1309,7 +1250,6 @@
 aconfig_declarations {
     name: "android.app.wearable.flags-aconfig",
     package: "android.app.wearable",
-    container: "system",
     srcs: ["core/java/android/app/wearable/*.aconfig"],
 }
 
@@ -1322,7 +1262,6 @@
 aconfig_declarations {
     name: "com.android.internal.pm.pkg.component.flags-aconfig",
     package: "com.android.internal.pm.pkg.component.flags",
-    container: "system",
     srcs: ["core/java/com/android/internal/pm/pkg/component/flags/flags.aconfig"],
 }
 
@@ -1343,7 +1282,6 @@
 aconfig_declarations {
     name: "android.systemserver.flags-aconfig",
     package: "android.server",
-    container: "system",
     srcs: ["services/java/com/android/server/flags.aconfig"],
 }
 
diff --git a/apex/jobscheduler/framework/aconfig/job.aconfig b/apex/jobscheduler/framework/aconfig/job.aconfig
index 80db264..2c1a853 100644
--- a/apex/jobscheduler/framework/aconfig/job.aconfig
+++ b/apex/jobscheduler/framework/aconfig/job.aconfig
@@ -1,5 +1,4 @@
 package: "android.app.job"
-container: "system"
 
 flag {
     name: "enforce_minimum_time_windows"
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index ace56d4..06c7d64 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -24,6 +24,7 @@
         "app-compat-annotations",
         "error_prone_annotations",
         "framework",
+        "keepanno-annotations",
         "services.core",
         "unsupportedappusage",
     ],
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index f9c8e0b..b982d12 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -1795,6 +1795,10 @@
 
         mUseFrozenStateToDropListenerAlarms = Flags.useFrozenStateToDropListenerAlarms();
         mStartUserBeforeScheduledAlarms = Flags.startUserBeforeScheduledAlarms();
+        if (mStartUserBeforeScheduledAlarms) {
+            mUserWakeupStore = new UserWakeupStore();
+            mUserWakeupStore.init();
+        }
         if (mUseFrozenStateToDropListenerAlarms) {
             final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> {
                 final int size = frozenStates.length;
@@ -1913,10 +1917,6 @@
                 Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
             }
         }
-        if (mStartUserBeforeScheduledAlarms) {
-            mUserWakeupStore = new UserWakeupStore();
-            mUserWakeupStore.init();
-        }
         publishLocalService(AlarmManagerInternal.class, new LocalService());
         publishBinderService(Context.ALARM_SERVICE, mService);
     }
@@ -3863,7 +3863,7 @@
         long nextNonWakeup = 0;
         if (mAlarmStore.size() > 0) {
             long firstWakeup = mAlarmStore.getNextWakeupDeliveryTime();
-            if (mStartUserBeforeScheduledAlarms) {
+            if (mStartUserBeforeScheduledAlarms && mUserWakeupStore != null) {
                 final long firstUserWakeup = mUserWakeupStore.getNextWakeupTime();
                 if (firstUserWakeup >= 0 && firstUserWakeup < firstWakeup) {
                     firstWakeup = firstUserWakeup;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 096238a..012ede2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -1737,17 +1737,6 @@
                     continue;
                 }
 
-                if (!nextPending.isReady()) {
-                    // This could happen when the job count reached its quota, the constrains
-                    // for the job has been updated but hasn't been removed from the pending
-                    // queue yet.
-                    if (DEBUG) {
-                        Slog.w(TAG, "Pending+not ready job: " + nextPending);
-                    }
-                    pendingJobQueue.remove(nextPending);
-                    continue;
-                }
-
                 if (DEBUG && isSimilarJobRunningLocked(nextPending)) {
                     Slog.w(TAG, "Already running similar job to: " + nextPending);
                 }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index cfbfa5d..3c9648b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -512,7 +512,7 @@
 
     /** An app has reached its quota. The message should contain a {@link UserPackage} object. */
     @VisibleForTesting
-    static final int MSG_REACHED_TIME_QUOTA = 0;
+    static final int MSG_REACHED_QUOTA = 0;
     /** Drop any old timing sessions. */
     private static final int MSG_CLEAN_UP_SESSIONS = 1;
     /** Check if a package is now within its quota. */
@@ -524,7 +524,7 @@
      * object.
      */
     @VisibleForTesting
-    static final int MSG_REACHED_EJ_TIME_QUOTA = 4;
+    static final int MSG_REACHED_EJ_QUOTA = 4;
     /**
      * Process a new {@link UsageEvents.Event}. The event will be the message's object and the
      * userId will the first arg.
@@ -533,11 +533,6 @@
     /** A UID's free quota grace period has ended. */
     @VisibleForTesting
     static final int MSG_END_GRACE_PERIOD = 6;
-    /**
-     * An app has reached its job count quota. The message should contain a {@link UserPackage}
-     * object.
-     */
-    static final int MSG_REACHED_COUNT_QUOTA = 7;
 
     public QuotaController(@NonNull JobSchedulerService service,
             @NonNull BackgroundJobsController backgroundJobsController,
@@ -879,37 +874,17 @@
     }
 
     @VisibleForTesting
-    @GuardedBy("mLock")
     boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
         final int standbyBucket = jobStatus.getEffectiveStandbyBucket();
         // A job is within quota if one of the following is true:
         //   1. it was started while the app was in the TOP state
         //   2. the app is currently in the foreground
         //   3. the app overall is within its quota
-        if (jobStatus.shouldTreatAsUserInitiatedJob()
+        return jobStatus.shouldTreatAsUserInitiatedJob()
                 || isTopStartedJobLocked(jobStatus)
-                || isUidInForeground(jobStatus.getSourceUid())) {
-            return true;
-        }
-
-        if (standbyBucket == NEVER_INDEX) return false;
-
-        if (isQuotaFreeLocked(standbyBucket)) return true;
-
-        final ExecutionStats stats = getExecutionStatsLocked(jobStatus.getSourceUserId(),
-                jobStatus.getSourcePackageName(), standbyBucket);
-        if (!(getRemainingExecutionTimeLocked(stats) > 0)) {
-            // Out of execution time quota.
-            return false;
-        }
-
-        if (mService.isCurrentlyRunningLocked(jobStatus)) {
-            // if job is running, considered as in quota so it can keep running.
-            return true;
-        }
-
-        // Check if the app is within job count quota.
-        return isUnderJobCountQuotaLocked(stats) && isUnderSessionCountQuotaLocked(stats);
+                || isUidInForeground(jobStatus.getSourceUid())
+                || isWithinQuotaLocked(
+                jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
     }
 
     @GuardedBy("mLock")
@@ -934,11 +909,12 @@
         ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
         // TODO: use a higher minimum remaining time for jobs with MINIMUM priority
         return getRemainingExecutionTimeLocked(stats) > 0
-                && isUnderJobCountQuotaLocked(stats)
-                && isUnderSessionCountQuotaLocked(stats);
+                && isUnderJobCountQuotaLocked(stats, standbyBucket)
+                && isUnderSessionCountQuotaLocked(stats, standbyBucket);
     }
 
-    private boolean isUnderJobCountQuotaLocked(@NonNull ExecutionStats stats) {
+    private boolean isUnderJobCountQuotaLocked(@NonNull ExecutionStats stats,
+            final int standbyBucket) {
         final long now = sElapsedRealtimeClock.millis();
         final boolean isUnderAllowedTimeQuota =
                 (stats.jobRateLimitExpirationTimeElapsed <= now
@@ -947,7 +923,8 @@
                 && stats.bgJobCountInWindow < stats.jobCountLimit;
     }
 
-    private boolean isUnderSessionCountQuotaLocked(@NonNull ExecutionStats stats) {
+    private boolean isUnderSessionCountQuotaLocked(@NonNull ExecutionStats stats,
+            final int standbyBucket) {
         final long now = sElapsedRealtimeClock.millis();
         final boolean isUnderAllowedTimeQuota = (stats.sessionRateLimitExpirationTimeElapsed <= now
                 || stats.sessionCountInRateLimitingWindow < mMaxSessionCountPerRateLimitingWindow);
@@ -1472,7 +1449,6 @@
                 stats.jobCountInRateLimitingWindow = 0;
             }
             stats.jobCountInRateLimitingWindow += count;
-            stats.bgJobCountInWindow += count;
         }
     }
 
@@ -1707,11 +1683,10 @@
                     changedJobs.add(js);
                 }
             } else if (realStandbyBucket != EXEMPTED_INDEX && realStandbyBucket != ACTIVE_INDEX
-                    && realStandbyBucket == js.getEffectiveStandbyBucket()
-                    && !mService.isCurrentlyRunningLocked(js)) {
+                    && realStandbyBucket == js.getEffectiveStandbyBucket()) {
                 // An app in the ACTIVE bucket may be out of quota while the job could be in quota
                 // for some reason. Therefore, avoid setting the real value here and check each job
-                // individually. Running job need to determine its own quota status as well.
+                // individually.
                 if (setConstraintSatisfied(js, nowElapsed, realInQuota, isWithinEJQuota)) {
                     changedJobs.add(js);
                 }
@@ -1830,8 +1805,9 @@
         }
 
         ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
-        final boolean isUnderJobCountQuota = isUnderJobCountQuotaLocked(stats);
-        final boolean isUnderTimingSessionCountQuota = isUnderSessionCountQuotaLocked(stats);
+        final boolean isUnderJobCountQuota = isUnderJobCountQuotaLocked(stats, standbyBucket);
+        final boolean isUnderTimingSessionCountQuota = isUnderSessionCountQuotaLocked(stats,
+                standbyBucket);
         final long remainingEJQuota = getRemainingEJExecutionTimeLocked(userId, packageName);
 
         final boolean inRegularQuota =
@@ -2150,11 +2126,6 @@
                 mBgJobCount++;
                 if (mRegularJobTimer) {
                     incrementJobCountLocked(mPkg.userId, mPkg.packageName, 1);
-                    final ExecutionStats stats = getExecutionStatsLocked(mPkg.userId,
-                            mPkg.packageName, jobStatus.getEffectiveStandbyBucket(), false);
-                    if (stats.bgJobCountInWindow >= stats.jobCountLimit) {
-                        mHandler.obtainMessage(MSG_REACHED_COUNT_QUOTA, mPkg).sendToTarget();
-                    }
                 }
                 if (mRunningBgJobs.size() == 1) {
                     // Started tracking the first job.
@@ -2286,6 +2257,7 @@
                     // repeatedly plugged in and unplugged, or an app changes foreground state
                     // very frequently, the job count for a package may be artificially high.
                     mBgJobCount = mRunningBgJobs.size();
+
                     if (mRegularJobTimer) {
                         incrementJobCountLocked(mPkg.userId, mPkg.packageName, mBgJobCount);
                         // Starting the timer means that all cached execution stats are now
@@ -2312,8 +2284,7 @@
                     return;
                 }
                 Message msg = mHandler.obtainMessage(
-                        mRegularJobTimer ? MSG_REACHED_TIME_QUOTA : MSG_REACHED_EJ_TIME_QUOTA,
-                        mPkg);
+                        mRegularJobTimer ? MSG_REACHED_QUOTA : MSG_REACHED_EJ_QUOTA, mPkg);
                 final long timeRemainingMs = mRegularJobTimer
                         ? getTimeUntilQuotaConsumedLocked(mPkg.userId, mPkg.packageName)
                         : getTimeUntilEJQuotaConsumedLocked(mPkg.userId, mPkg.packageName);
@@ -2330,7 +2301,7 @@
 
         private void cancelCutoff() {
             mHandler.removeMessages(
-                    mRegularJobTimer ? MSG_REACHED_TIME_QUOTA : MSG_REACHED_EJ_TIME_QUOTA, mPkg);
+                    mRegularJobTimer ? MSG_REACHED_QUOTA : MSG_REACHED_EJ_QUOTA, mPkg);
         }
 
         public void dump(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
@@ -2586,7 +2557,7 @@
                     break;
                 default:
                     if (DEBUG) {
-                        Slog.d(TAG, "Dropping usage event " + event.getEventType());
+                        Slog.d(TAG, "Dropping event " + event.getEventType());
                     }
                     break;
             }
@@ -2695,7 +2666,7 @@
         public void handleMessage(Message msg) {
             synchronized (mLock) {
                 switch (msg.what) {
-                    case MSG_REACHED_TIME_QUOTA: {
+                    case MSG_REACHED_QUOTA: {
                         UserPackage pkg = (UserPackage) msg.obj;
                         if (DEBUG) {
                             Slog.d(TAG, "Checking if " + pkg + " has reached its quota.");
@@ -2714,7 +2685,7 @@
                             // This could potentially happen if an old session phases out while a
                             // job is currently running.
                             // Reschedule message
-                            Message rescheduleMsg = obtainMessage(MSG_REACHED_TIME_QUOTA, pkg);
+                            Message rescheduleMsg = obtainMessage(MSG_REACHED_QUOTA, pkg);
                             timeRemainingMs = getTimeUntilQuotaConsumedLocked(pkg.userId,
                                     pkg.packageName);
                             if (DEBUG) {
@@ -2724,7 +2695,7 @@
                         }
                         break;
                     }
-                    case MSG_REACHED_EJ_TIME_QUOTA: {
+                    case MSG_REACHED_EJ_QUOTA: {
                         UserPackage pkg = (UserPackage) msg.obj;
                         if (DEBUG) {
                             Slog.d(TAG, "Checking if " + pkg + " has reached its EJ quota.");
@@ -2742,7 +2713,7 @@
                             // This could potentially happen if an old session phases out while a
                             // job is currently running.
                             // Reschedule message
-                            Message rescheduleMsg = obtainMessage(MSG_REACHED_EJ_TIME_QUOTA, pkg);
+                            Message rescheduleMsg = obtainMessage(MSG_REACHED_EJ_QUOTA, pkg);
                             timeRemainingMs = getTimeUntilEJQuotaConsumedLocked(
                                     pkg.userId, pkg.packageName);
                             if (DEBUG) {
@@ -2752,18 +2723,6 @@
                         }
                         break;
                     }
-                    case MSG_REACHED_COUNT_QUOTA: {
-                        UserPackage pkg = (UserPackage) msg.obj;
-                        if (DEBUG) {
-                            Slog.d(TAG, pkg + " has reached its count quota.");
-                        }
-
-                        mStateChangedListener.onControllerStateChanged(
-                                maybeUpdateConstraintForPkgLocked(
-                                        sElapsedRealtimeClock.millis(),
-                                        pkg.userId, pkg.packageName));
-                        break;
-                    }
                     case MSG_CLEAN_UP_SESSIONS:
                         if (DEBUG) {
                             Slog.d(TAG, "Cleaning up timing sessions.");
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 19bc716..613678b 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -130,6 +130,8 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.usage.AppIdleHistory.AppUsageHistory;
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.UsedByReflection;
 
 import libcore.util.EmptyArray;
 
@@ -588,6 +590,8 @@
         }
     }
 
+    // This constructor is reflectively invoked from framework code in AppStandbyInternal.
+    @UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS)
     public AppStandbyController(Context context) {
         this(new Injector(context, AppSchedulingModuleThread.get().getLooper()));
     }
diff --git a/apex/jobscheduler/service/jni/Android.bp b/apex/jobscheduler/service/jni/Android.bp
index 34a1fa2..e8acff7 100644
--- a/apex/jobscheduler/service/jni/Android.bp
+++ b/apex/jobscheduler/service/jni/Android.bp
@@ -28,4 +28,8 @@
         "liblog",
         "libbase",
     ],
+    visibility: [
+        "//frameworks/base/apex:__subpackages__",
+        "//visibility:any_system_partition",
+    ],
 }
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
index 7a449ef..af54a2d 100644
--- a/cmds/locksettings/TEST_MAPPING
+++ b/cmds/locksettings/TEST_MAPPING
@@ -11,5 +11,10 @@
                 }
             ]
         }
+    ],
+    "postsubmit": [
+        {
+            "name": "CtsDevicePolicyManagerTestCases_LockSettings_NoFlakes"
+        }
     ]
 }
diff --git a/core/java/android/adaptiveauth/flags.aconfig b/core/java/android/adaptiveauth/flags.aconfig
index b9cf29c..de4e607 100644
--- a/core/java/android/adaptiveauth/flags.aconfig
+++ b/core/java/android/adaptiveauth/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.adaptiveauth"
-container: "system"
 
 flag {
   name: "enable_adaptive_auth"
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index e4425ca..e751bd2 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
      namespace: "system_performance"
diff --git a/core/java/android/app/admin/Provisioning_OWNERS b/core/java/android/app/admin/Provisioning_OWNERS
index 8f71fc0..91b9761 100644
--- a/core/java/android/app/admin/Provisioning_OWNERS
+++ b/core/java/android/app/admin/Provisioning_OWNERS
@@ -1,4 +1,4 @@
 # Assign bugs to android-enterprise-triage@google.com
 ae-provisioning-reviews@google.com
-petuska@google.com #{LAST_RESORT_SUGGESTION}
+acjohnston@google.com #{LAST_RESORT_SUGGESTION}
 file:EnterprisePlatform_OWNERS
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 56fb4aa..fe2f764 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -2,7 +2,6 @@
 # proto-message: flag_declarations
 
 package: "android.app.admin.flags"
-container: "system"
 
 flag {
   name: "policy_engine_migration_v2_enabled"
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
index d29c5b5..5f3bb07 100644
--- a/core/java/android/app/background_install_control_manager.aconfig
+++ b/core/java/android/app/background_install_control_manager.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
      namespace: "preload_safety"
diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig
index 3385b2b..5ab0762 100644
--- a/core/java/android/app/contextualsearch/flags.aconfig
+++ b/core/java/android/app/contextualsearch/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.app.contextualsearch.flags"
-container: "system"
 
 flag {
   name: "enable_service"
diff --git a/core/java/android/app/grammatical_inflection_manager.aconfig b/core/java/android/app/grammatical_inflection_manager.aconfig
index ea494f4..0d7bf65 100644
--- a/core/java/android/app/grammatical_inflection_manager.aconfig
+++ b/core/java/android/app/grammatical_inflection_manager.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
     name: "system_terms_of_address_enabled"
diff --git a/core/java/android/app/multitasking.aconfig b/core/java/android/app/multitasking.aconfig
index 9a64519..dbf3173 100644
--- a/core/java/android/app/multitasking.aconfig
+++ b/core/java/android/app/multitasking.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
     name: "enable_pip_ui_state_callback_on_entering"
diff --git a/core/java/android/app/network-policy.aconfig b/core/java/android/app/network-policy.aconfig
index e7b02a7..88f386f 100644
--- a/core/java/android/app/network-policy.aconfig
+++ b/core/java/android/app/network-policy.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
      namespace: "backstage_power"
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 0082732..0214d40 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
   name: "modes_api"
diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
index 8b6441a..dd9210f 100644
--- a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
+++ b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
@@ -1,5 +1,4 @@
 package: "android.app.ondeviceintelligence.flags"
-container: "system"
 
 flag {
     name: "enable_on_device_intelligence"
diff --git a/core/java/android/app/pinner-client.aconfig b/core/java/android/app/pinner-client.aconfig
index 696fd38..0f7fa14 100644
--- a/core/java/android/app/pinner-client.aconfig
+++ b/core/java/android/app/pinner-client.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
      namespace: "system_performance"
diff --git a/core/java/android/app/smartspace/flags.aconfig b/core/java/android/app/smartspace/flags.aconfig
index df71924..e90ba67 100644
--- a/core/java/android/app/smartspace/flags.aconfig
+++ b/core/java/android/app/smartspace/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.app.smartspace.flags"
-container: "system"
 
 flag {
   name: "remote_views"
diff --git a/core/java/android/app/ui_mode_manager.aconfig b/core/java/android/app/ui_mode_manager.aconfig
index 9f44a4d..27a38cc 100644
--- a/core/java/android/app/ui_mode_manager.aconfig
+++ b/core/java/android/app/ui_mode_manager.aconfig
@@ -1,5 +1,4 @@
 package: "android.app"
-container: "system"
 
 flag {
      namespace: "systemui"
diff --git a/core/java/android/app/usage/flags.aconfig b/core/java/android/app/usage/flags.aconfig
index c7b168a..9a2d2e5 100644
--- a/core/java/android/app/usage/flags.aconfig
+++ b/core/java/android/app/usage/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.app.usage"
-container: "system"
 
 flag {
     name: "user_interaction_type_api"
diff --git a/core/java/android/app/wearable/flags.aconfig b/core/java/android/app/wearable/flags.aconfig
index b68bafe..d1d7b5d 100644
--- a/core/java/android/app/wearable/flags.aconfig
+++ b/core/java/android/app/wearable/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.app.wearable"
-container: "system"
 
 flag {
     name: "enable_unsupported_operation_status_code"
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 3bcc7c7..765c802 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.appwidget.flags"
-container: "system"
 
 flag {
   name: "generated_previews"
@@ -33,3 +32,10 @@
   description: "Enable support for transporting draw instructions as data parcel"
   bug: "286130467"
 }
+
+flag {
+  name: "throttle_widget_updates"
+  namespace: "app_widgets"
+  description: "Throttle the widget view updates to mitigate transaction exceptions"
+  bug: "326145514"
+}
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index 8458857..ecc5e1b 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.companion"
-container: "system"
 
 flag {
     name: "new_association_builder"
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 18c81a2..e6649df 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -8,7 +8,6 @@
 # instead.
 
 package: "android.companion.virtual.flags"
-container: "system"
 
 flag {
   name: "enable_native_vdm"
@@ -117,3 +116,14 @@
   description: "Enable virtual stylus input"
   bug: "304829446"
 }
+
+flag {
+  name: "intercept_intents_before_applying_policy"
+  is_exported: true
+  namespace: "virtual_devices"
+  description: "Apply intent interception before applying activity policy"
+  bug: "333444131"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
\ No newline at end of file
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index 006226e..2904e7c 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -14,7 +14,6 @@
 # limitations under the License.
 
 package: "android.companion.virtualdevice.flags"
-container: "system"
 
 flag {
      namespace: "virtual_devices"
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b706cae..bad73fc 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3256,6 +3256,14 @@
      *
      * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
      *
+     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a
+     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place
+     * context-registered broadcasts in a queue while the app is in the <a
+     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>.
+     * When the app leaves the cached state, such as returning to the
+     * foreground, the system delivers any queued broadcasts. Multiple instances
+     * of certain broadcasts might be merged into one broadcast.
+     *
      * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers
      * registered with this method will correctly respect the
      * {@link Intent#setPackage(String)} specified for an Intent being broadcast.
@@ -3301,6 +3309,14 @@
      *
      * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
      *
+     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a
+     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place
+     * context-registered broadcasts in a queue while the app is in the <a
+     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>.
+     * When the app leaves the cached state, such as returning to the
+     * foreground, the system delivers any queued broadcasts. Multiple instances
+     * of certain broadcasts might be merged into one broadcast.
+     *
      * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers
      * registered with this method will correctly respect the
      * {@link Intent#setPackage(String)} specified for an Intent being broadcast.
@@ -3342,6 +3358,14 @@
      *
      * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
      *
+     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a
+     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place
+     * context-registered broadcasts in a queue while the app is in the <a
+     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>.
+     * When the app leaves the cached state, such as returning to the
+     * foreground, the system delivers any queued broadcasts. Multiple instances
+     * of certain broadcasts might be merged into one broadcast.
+     *
      * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers
      * registered with this method will correctly respect the
      * {@link Intent#setPackage(String)} specified for an Intent being broadcast.
@@ -3385,6 +3409,14 @@
      *
      * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
      *
+     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a
+     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place
+     * context-registered broadcasts in a queue while the app is in the <a
+     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>.
+     * When the app leaves the cached state, such as returning to the
+     * foreground, the system delivers any queued broadcasts. Multiple instances
+     * of certain broadcasts might be merged into one broadcast.
+     *
      * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers
      * registered with this method will correctly respect the
      * {@link Intent#setPackage(String)} specified for an Intent being broadcast.
diff --git a/core/java/android/content/flags/flags.aconfig b/core/java/android/content/flags/flags.aconfig
index aac04b3a..27bce5b 100644
--- a/core/java/android/content/flags/flags.aconfig
+++ b/core/java/android/content/flags/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.content.flags"
-container: "system"
 
 flag {
     name: "enable_bind_package_isolated_process"
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 6158917..cde565b 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.content.pm"
-container: "system"
 
 flag {
     name: "quarantined_enabled"
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 0c0da31..4963a4f 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -1,5 +1,4 @@
 package: "android.multiuser"
-container: "system"
 
 flag {
     name: "save_global_and_guest_restrictions_on_system_user_xml"
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index a475cc8..8f5c912 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.content.res"
-container: "system"
 
 flag {
     name: "default_locale"
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index 93fa5d8..eb7afb8e 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -61,7 +61,9 @@
 @SystemService(Context.CREDENTIAL_SERVICE)
 @RequiresFeature(PackageManager.FEATURE_CREDENTIALS)
 public final class CredentialManager {
-    private static final String TAG = "CredentialManager";
+    /** @hide **/
+    @Hide
+    public static final String TAG = "CredentialManager";
     private static final Bundle OPTIONS_SENDER_BAL_OPTIN = ActivityOptions.makeBasic()
             .setPendingIntentBackgroundActivityStartMode(
                     ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle();
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index d243575..d077329 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.credentials.flags"
-container: "system"
 
 flag {
     namespace: "credential_manager"
diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig
index 3073e25..7ecffaf 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.database.sqlite"
-container: "system"
 
 flag {
      name: "sqlite_apis_35"
diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig
index 4284ad0..9836eec 100644
--- a/core/java/android/hardware/biometrics/flags.aconfig
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.hardware.biometrics"
-container: "system"
 
 flag {
     name: "last_authentication_time"
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index dca663d..50d976f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -1768,9 +1768,12 @@
          * @param sessionConfig The session configuration for which characteristics are fetched.
          * @return CameraCharacteristics specific to a given session configuration.
          *
-         * @throws IllegalArgumentException      if the session configuration is invalid
-         * @throws CameraAccessException         if the camera device is no longer connected or has
-         *                                       encountered a fatal error
+         * @throws IllegalArgumentException if the session configuration is invalid or if
+         *                                  {@link #isSessionConfigurationSupported} returns
+         *                                  {@code false} for the provided
+         *                                  {@link SessionConfiguration}
+         * @throws CameraAccessException    if the camera device is no longer connected or has
+         *                                  encountered a fatal error
          *
          * @see CameraCharacteristics#getAvailableSessionCharacteristicsKeys
          */
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
index 81d0976..372839d 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
@@ -104,8 +104,8 @@
             }
 
             try {
-                return cameraService.isSessionConfigurationWithParametersSupported(
-                        mCameraId, config, mContext.getDeviceId(),
+                return cameraService.isSessionConfigurationWithParametersSupported(mCameraId,
+                        mTargetSdkVersion, config, mContext.getDeviceId(),
                         mCameraManager.getDevicePolicyFromContext(mContext));
             } catch (ServiceSpecificException e) {
                 throw ExceptionUtils.throwAsPublicException(e);
diff --git a/core/java/android/hardware/devicestate/feature/flags.aconfig b/core/java/android/hardware/devicestate/feature/flags.aconfig
index 12d3f94..e474603 100644
--- a/core/java/android/hardware/devicestate/feature/flags.aconfig
+++ b/core/java/android/hardware/devicestate/feature/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.hardware.devicestate.feature.flags"
-container: "system"
 
 flag {
     name: "device_state_property_api"
diff --git a/core/java/android/hardware/flags/overlayproperties_flags.aconfig b/core/java/android/hardware/flags/overlayproperties_flags.aconfig
index 6c86108..1165e65 100644
--- a/core/java/android/hardware/flags/overlayproperties_flags.aconfig
+++ b/core/java/android/hardware/flags/overlayproperties_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.hardware.flags"
-container: "system"
 
 flag {
     name: "overlayproperties_class_api"
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index ed536ce..9684e64 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.hardware.input"
-container: "system"
 
 # Project link: https://gantry.corp.google.com/projects/android_platform_input_native/changes
 
diff --git a/core/java/android/hardware/radio/flags.aconfig b/core/java/android/hardware/radio/flags.aconfig
index c9ab62d..d0d10c1 100644
--- a/core/java/android/hardware/radio/flags.aconfig
+++ b/core/java/android/hardware/radio/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.hardware.radio"
-container: "system"
 
 flag {
     name: "hd_radio_improved"
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 967fc42..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
@@ -1,5 +1,4 @@
 package: "android.hardware.usb.flags"
-container: "system"
 
 flag {
     name: "enable_usb_data_compliance_warning"
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 94df160..3dd746c 100644
--- a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.hardware.usb.flags"
-container: "system"
 
 flag {
     name: "enable_is_pd_compliant_api"
diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig
index 048c50e..3544a69 100644
--- a/core/java/android/net/flags.aconfig
+++ b/core/java/android/net/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.net.platform.flags"
-container: "system"
 
 # This file contains aconfig flags used from platform code
 # Flags used for module APIs must be in aconfig files under each modules
diff --git a/core/java/android/net/thread/flags.aconfig b/core/java/android/net/thread/flags.aconfig
index afb982b..ef798ad 100644
--- a/core/java/android/net/thread/flags.aconfig
+++ b/core/java/android/net/thread/flags.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.net.thread.platform.flags"
-container: "system"
 
 # This file contains aconfig flags used from platform code
 # Flags used for module APIs must be in aconfig files under each modules
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index 15d671d..e64823a 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.net.vcn"
-container: "system"
 
 flag {
     name: "safe_mode_config"
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f172c3e..857a85d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -705,7 +705,7 @@
      * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_BLUETOOTH}
      * can set this restriction using the DevicePolicyManager APIs mentioned below.
      *
-     * <p>Default is <code>true</code> for managed profiles and false otherwise.
+     * <p>Default is <code>true</code> for managed and private profiles, false otherwise.
      *
      * <p>When a device upgrades to {@link android.os.Build.VERSION_CODES#O}, the system sets it
      * for all existing managed profiles.
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index fd955e2..f26a797 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -1,6 +1,5 @@
 package: "android.os"
 container: "system"
-container: "system"
 
 flag {
     name: "android_os_build_vanilla_ice_cream"
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt b/core/java/android/os/storage/ICeStorageLockEventListener.java
similarity index 66%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
copy to core/java/android/os/storage/ICeStorageLockEventListener.java
index f6140f5..f16a7fe 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
+++ b/core/java/android/os/storage/ICeStorageLockEventListener.java
@@ -14,9 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.credentialmanager.common
+package android.os.storage;
 
-enum class FlowType {
-    GET,
-    CREATE
-}
\ No newline at end of file
+
+/**
+ * Callback class for receiving CE storage lock events from StorageManagerService.
+ * @hide
+ */
+public interface ICeStorageLockEventListener {
+
+    /**
+     * Called when the CE storage corresponding to the userId is locked
+     */
+    void onStorageLocked(int userId);
+}
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 6995ea8..8ba2fa4 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -16,10 +16,12 @@
 
 package android.os.storage;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.pm.UserInfo;
+import android.multiuser.Flags;
 import android.os.IInstalld;
 import android.os.IVold;
 import android.os.ParcelFileDescriptor;
@@ -201,4 +203,18 @@
      */
     public abstract int enableFsverity(IInstalld.IFsveritySetupAuthToken authToken, String filePath,
             String packageName) throws IOException;
+
+    /**
+     * Registers a {@link ICeStorageLockEventListener} for receiving CE storage lock events.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE)
+    public abstract void registerStorageLockEventListener(
+            @NonNull ICeStorageLockEventListener listener);
+
+    /**
+     * Unregisters the {@link ICeStorageLockEventListener} which was registered previously
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE)
+    public abstract void unregisterStorageLockEventListener(
+            @NonNull ICeStorageLockEventListener listener);
 }
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index eda755c..229d119 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.os.vibrator"
-container: "system"
 
 flag {
     namespace: "haptics"
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index c26f351..ec3c978 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.permission.flags"
-container: "system"
 
 flag {
   name: "device_aware_permission_apis_enabled"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 267a9d3..dd93972 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10980,7 +10980,7 @@
                 "biometric_debug_enabled";
 
         /**
-         * Whether or not virtual sensors are enabled.
+         * Whether or not both fingerprint and face virtual sensors are enabled.
          * @hide
          */
         @TestApi
@@ -10988,6 +10988,22 @@
         public static final String BIOMETRIC_VIRTUAL_ENABLED = "biometric_virtual_enabled";
 
         /**
+         * Whether or not fingerprint virtual sensors are enabled.
+         * @hide
+         */
+        @FlaggedApi("com.android.server.biometrics.face_vhal_feature")
+        public static final String BIOMETRIC_FINGERPRINT_VIRTUAL_ENABLED =
+                "biometric_fingerprint_virtual_enabled";
+
+        /**
+         * Whether or not face virtual sensors are enabled.
+         * @hide
+         */
+        @FlaggedApi("com.android.server.biometrics.face_vhal_feature")
+        public static final String BIOMETRIC_FACE_VIRTUAL_ENABLED =
+                "biometric_face_virtual_enabled";
+
+        /**
          * Whether or not biometric is allowed on Keyguard.
          * @hide
          */
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index 77353c2..d0cef83 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.provider"
-container: "system"
 
 flag {
     name: "a11y_standalone_fab_enabled"
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 02e787b..7f5b550 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.security"
-container: "system"
 
 flag {
     name: "certificate_transparency_configuration"
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index c7d951b..548f8aa 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.security"
-container: "system"
 
 flag {
     name: "extend_ecm_to_all_settings"
diff --git a/core/java/android/service/appprediction/flags/flags.aconfig b/core/java/android/service/appprediction/flags/flags.aconfig
index 953bc44..7f9764e 100644
--- a/core/java/android/service/appprediction/flags/flags.aconfig
+++ b/core/java/android/service/appprediction/flags/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.service.appprediction.flags"
-container: "system"
 
 flag {
   name: "service_features_api"
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index d6425c3..a3eff3b 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.service.chooser"
-container: "system"
 
 flag {
   name: "chooser_album_text"
diff --git a/core/java/android/service/controls/flags/flags.aconfig b/core/java/android/service/controls/flags/flags.aconfig
index 6f3a67d..197f1bc 100644
--- a/core/java/android/service/controls/flags/flags.aconfig
+++ b/core/java/android/service/controls/flags/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.service.controls.flags"
-container: "system"
 
 flag {
     name: "home_panel_dream"
diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
index c6d3d9b..92f2c32 100644
--- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java
+++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
@@ -65,7 +65,7 @@
  * @hide
  */
 public final class CredentialProviderInfoFactory {
-    private static final String TAG = "CredentialProviderInfoFactory";
+    private static final String TAG = CredentialManager.TAG;
 
     private static final String TAG_CREDENTIAL_PROVIDER = "credential-provider";
     private static final String TAG_CAPABILITIES = "capabilities";
diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig
index 2f45f34..cca4937 100644
--- a/core/java/android/service/dreams/flags.aconfig
+++ b/core/java/android/service/dreams/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.service.dreams"
-container: "system"
 
 flag {
   name: "dream_overlay_host"
@@ -11,7 +10,7 @@
 
 flag {
   name: "dream_handles_confirm_keys"
-  namespace: "dreams"
+  namespace: "communal"
   description: "This flag enables dreams processing confirm keys to show the bouncer or dismiss "
        "the keyguard"
   bug: "326975875"
diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig
index b0c55a9..35cd3ed 100644
--- a/core/java/android/service/notification/flags.aconfig
+++ b/core/java/android/service/notification/flags.aconfig
@@ -1,6 +1,5 @@
 package: "android.service.notification"
 container: "system"
-container: "system"
 
 flag {
   name: "ranking_update_ashmem"
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
index 357cb47..1ae7d8c 100644
--- a/core/java/android/service/voice/flags/flags.aconfig
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.service.voice.flags"
-container: "system"
 
 flag {
     name: "allow_training_data_egress_from_hds"
diff --git a/core/java/android/speech/flags/speech_flags.aconfig b/core/java/android/speech/flags/speech_flags.aconfig
index 2a42357..fa33592 100644
--- a/core/java/android/speech/flags/speech_flags.aconfig
+++ b/core/java/android/speech/flags/speech_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.speech.flags"
-container: "system"
 
 flag {
     name: "multilang_extra_launch"
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index a8a0c5b..24035af 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.text.flags"
-container: "system"
 
 flag {
   name: "vendor_custom_locale_fallback"
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index c50c384..1815f14 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.tracing"
-container: "system"
 
 flag {
     name: "perfetto_transition_tracing"
diff --git a/core/java/android/tracing/perfetto/DataSource.java b/core/java/android/tracing/perfetto/DataSource.java
index d0c719b..c33fa7d 100644
--- a/core/java/android/tracing/perfetto/DataSource.java
+++ b/core/java/android/tracing/perfetto/DataSource.java
@@ -20,6 +20,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import dalvik.annotation.optimization.CriticalNative;
+
 /**
  * Templated base class meant to be derived by embedders to create a custom data
  * source.
@@ -71,9 +73,24 @@
      * @param fun The tracing lambda that will be called with the tracing contexts of each active
      *            tracing instance.
      */
-    public final void trace(
-            TraceFunction<DataSourceInstanceType, TlsStateType, IncrementalStateType> fun) {
-        nativeTrace(mNativeObj, fun);
+    public final void trace(TraceFunction<TlsStateType, IncrementalStateType> fun) {
+        boolean startedIterator = nativePerfettoDsTraceIterateBegin(mNativeObj);
+
+        if (!startedIterator) {
+            return;
+        }
+
+        try {
+            do {
+                TracingContext<TlsStateType, IncrementalStateType> ctx =
+                        new TracingContext<>(mNativeObj);
+                fun.trace(ctx);
+
+                ctx.flush();
+            } while (nativePerfettoDsTraceIterateNext(mNativeObj));
+        } finally {
+            nativePerfettoDsTraceIterateBreak(mNativeObj);
+        }
     }
 
     /**
@@ -154,8 +171,6 @@
             long dataSourcePtr, int bufferExhaustedPolicy);
 
     private static native long nativeCreate(DataSource thiz, String name);
-    private static native void nativeTrace(
-            long nativeDataSourcePointer, TraceFunction traceFunction);
     private static native void nativeFlushAll(long nativeDataSourcePointer);
     private static native long nativeGetFinalizer();
 
@@ -163,4 +178,11 @@
             long dataSourcePtr, int dsInstanceIdx);
     private static native void nativeReleasePerfettoInstanceLocked(
             long dataSourcePtr, int dsInstanceIdx);
+
+    @CriticalNative
+    private static native boolean nativePerfettoDsTraceIterateBegin(long dataSourcePtr);
+    @CriticalNative
+    private static native boolean nativePerfettoDsTraceIterateNext(long dataSourcePtr);
+    @CriticalNative
+    private static native void nativePerfettoDsTraceIterateBreak(long dataSourcePtr);
 }
diff --git a/core/java/android/tracing/perfetto/TraceFunction.java b/core/java/android/tracing/perfetto/TraceFunction.java
index 62941df..13e663d 100644
--- a/core/java/android/tracing/perfetto/TraceFunction.java
+++ b/core/java/android/tracing/perfetto/TraceFunction.java
@@ -16,19 +16,15 @@
 
 package android.tracing.perfetto;
 
-import java.io.IOException;
-
 /**
  * The interface for the trace function called from native on a trace call with a context.
  *
- * @param <DataSourceInstanceType> The type of DataSource this tracing context is for.
  * @param <TlsStateType> The type of the custom TLS state, if any is used.
  * @param <IncrementalStateType> The type of the custom incremental state, if any is used.
  *
  * @hide
  */
-public interface TraceFunction<DataSourceInstanceType extends DataSourceInstance,
-        TlsStateType, IncrementalStateType> {
+public interface TraceFunction<TlsStateType, IncrementalStateType> {
 
     /**
      * This function will be called synchronously (i.e., always before trace() returns) only if
@@ -38,6 +34,5 @@
      *
      * @param ctx the tracing context to trace for in the trace function.
      */
-    void trace(TracingContext<DataSourceInstanceType, TlsStateType, IncrementalStateType> ctx)
-            throws IOException;
+    void trace(TracingContext<TlsStateType, IncrementalStateType> ctx);
 }
diff --git a/core/java/android/tracing/perfetto/TracingContext.java b/core/java/android/tracing/perfetto/TracingContext.java
index c1a61a7..060f964 100644
--- a/core/java/android/tracing/perfetto/TracingContext.java
+++ b/core/java/android/tracing/perfetto/TracingContext.java
@@ -24,26 +24,18 @@
 /**
  * Argument passed to the lambda function passed to Trace().
  *
- * @param <DataSourceInstanceType> The type of the datasource this tracing context is for.
  * @param <TlsStateType> The type of the custom TLS state, if any is used.
  * @param <IncrementalStateType> The type of the custom incremental state, if any is used.
  *
  * @hide
  */
-public class TracingContext<DataSourceInstanceType extends DataSourceInstance,
-        TlsStateType, IncrementalStateType> {
+public class TracingContext<TlsStateType, IncrementalStateType> {
 
-    private final long mContextPtr;
-    private final TlsStateType mTlsState;
-    private final IncrementalStateType mIncrementalState;
+    private final long mNativeDsPtr;
     private final List<ProtoOutputStream> mTracePackets = new ArrayList<>();
 
-    // Should only be created from the native side.
-    private TracingContext(long contextPtr, TlsStateType tlsState,
-            IncrementalStateType incrementalState) {
-        this.mContextPtr = contextPtr;
-        this.mTlsState = tlsState;
-        this.mIncrementalState = incrementalState;
+    TracingContext(long nativeDsPtr) {
+        this.mNativeDsPtr = nativeDsPtr;
     }
 
     /**
@@ -69,7 +61,7 @@
      * Stop timeout expires.
      */
     public void flush() {
-        nativeFlush(this, mContextPtr);
+        nativeFlush(mNativeDsPtr, getAndClearAllPendingTracePackets());
     }
 
     /**
@@ -80,7 +72,7 @@
      * @return The TlsState instance for the tracing thread and instance.
      */
     public TlsStateType getCustomTlsState() {
-        return this.mTlsState;
+        return (TlsStateType) nativeGetCustomTls(mNativeDsPtr);
     }
 
     /**
@@ -90,10 +82,9 @@
      * @return The current IncrementalState object instance.
      */
     public IncrementalStateType getIncrementalState() {
-        return this.mIncrementalState;
+        return (IncrementalStateType) nativeGetIncrementalState(mNativeDsPtr);
     }
 
-    // Called from native to get trace packets
     private byte[][] getAndClearAllPendingTracePackets() {
         byte[][] res = new byte[mTracePackets.size()][];
         for (int i = 0; i < mTracePackets.size(); i++) {
@@ -105,5 +96,7 @@
         return res;
     }
 
-    private static native void nativeFlush(TracingContext thiz, long ctxPointer);
+    private static native void nativeFlush(long dataSourcePtr, byte[][] packetData);
+    private static native Object nativeGetCustomTls(long nativeDsPtr);
+    private static native Object nativeGetIncrementalState(long nativeDsPtr);
 }
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index f4aef22..334965a 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.accessibility"
-container: "system"
 
 # NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
 
@@ -81,6 +80,16 @@
 }
 
 flag {
+    name: "migrate_enable_shortcuts"
+    namespace: "accessibility"
+    description: "Refactors deprecated code to use AccessibilityManager#enableShortcutsForTargets."
+    bug: "332006721"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "motion_event_observing"
     is_exported: true
     namespace: "accessibility"
diff --git a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
index 416a877..3c15518 100644
--- a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
+++ b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.contentcapture.flags"
-container: "system"
 
 flag {
     name: "run_on_background_thread_enabled"
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 b3bd92b..4de0f29 100644
--- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
+++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.contentprotection.flags"
-container: "system"
 
 flag {
     name: "blocklist_update_enabled"
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index d0fe3e0..1047131 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.flags"
-container: "system"
 
 flag {
     name: "view_velocity_api"
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index 338037f..a7c4104 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.flags"
-container: "system"
 
 flag {
     namespace: "toolkit"
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index e8e02ec..c482f8b 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.flags"
-container: "system"
 
 flag {
     name: "enable_surface_native_alloc_registration_ro"
diff --git a/core/java/android/view/flags/window_insets.aconfig b/core/java/android/view/flags/window_insets.aconfig
index bedb7d5..bf6df5c 100644
--- a/core/java/android/view/flags/window_insets.aconfig
+++ b/core/java/android/view/flags/window_insets.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.flags"
-container: "system"
 
 flag {
     name: "customizable_window_headers"
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index d79903b..0d19746 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.view.inputmethod"
-container: "system"
 
 flag {
     name: "refactor_insets_controller"
diff --git a/core/java/android/webkit/flags.aconfig b/core/java/android/webkit/flags.aconfig
index defe61e..2d834a8 100644
--- a/core/java/android/webkit/flags.aconfig
+++ b/core/java/android/webkit/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.webkit"
-container: "system"
 
 flag {
     name: "update_service_ipc_wrapper"
diff --git a/core/java/android/widget/flags/differential_motion_fling_flags.aconfig b/core/java/android/widget/flags/differential_motion_fling_flags.aconfig
index a0a391e..79cfe56 100644
--- a/core/java/android/widget/flags/differential_motion_fling_flags.aconfig
+++ b/core/java/android/widget/flags/differential_motion_fling_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.widget.flags"
-container: "system"
 
 flag {
     namespace: "toolkit"
diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig
index b530e71..e60fa15 100644
--- a/core/java/android/widget/flags/notification_widget_flags.aconfig
+++ b/core/java/android/widget/flags/notification_widget_flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.widget.flags"
-container: "system"
 
 flag {
    name: "notif_linearlayout_optimized"
diff --git a/core/java/android/window/flags/accessibility.aconfig b/core/java/android/window/flags/accessibility.aconfig
index 733e3db..368c609 100644
--- a/core/java/android/window/flags/accessibility.aconfig
+++ b/core/java/android/window/flags/accessibility.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 flag {
   name: "do_not_check_intersection_when_non_magnifiable_window_transitions"
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 98ff3c6..fa0dab0 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
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 flag {
   name: "allows_screen_size_decoupled_from_status_bar_and_cutout"
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 616004b..9524a6e 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 flag {
     name: "enable_scaled_resizing"
@@ -43,3 +42,10 @@
     description: "Enables edge drag resizing for all input sources"
     bug: "323383067"
 }
+
+flag {
+    name: "enable_desktop_windowing_taskbar_running_apps"
+    namespace: "lse_desktop_experience"
+    description: "Shows running apps in Desktop Mode Taskbar"
+    bug: "332504528"
+}
diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig
index 33af486..94c72c6 100644
--- a/core/java/android/window/flags/responsible_apis.aconfig
+++ b/core/java/android/window/flags/responsible_apis.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 flag {
     name: "bal_require_opt_in_by_pending_intent_creator"
diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig
index 150b04e..edf90b5 100644
--- a/core/java/android/window/flags/wallpaper_manager.aconfig
+++ b/core/java/android/window/flags/wallpaper_manager.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 flag {
     name: "always_update_wallpaper_permission"
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 460df31..5c31048 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 # Project link: https://gantry.corp.google.com/projects/android_platform_window_surfaces/changes
 
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 87c47da..e2efff3 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 flag {
   name: "nav_bar_transparent_by_default"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 80265ec..4b3d8e8 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.window.flags"
-container: "system"
 
 # Project link: https://gantry.corp.google.com/projects/android_platform_windowing_sdk/changes
 
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index ddb8ee0..e531bcb 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -366,7 +366,7 @@
                                 // to the Settings.
                                 final ComponentName configDefaultService =
                                         ComponentName.unflattenFromString(defaultService);
-                                if (Flags.a11yQsShortcut()) {
+                                if (Flags.migrateEnableShortcuts()) {
                                     am.enableShortcutsForTargets(true, HARDWARE,
                                             Set.of(configDefaultService.flattenToString()), userId);
                                 } else {
@@ -384,7 +384,7 @@
                                             mContext,
                                             HARDWARE,
                                             userId);
-                            if (Flags.a11yQsShortcut()) {
+                            if (Flags.migrateEnableShortcuts()) {
                                 am.enableShortcutsForTargets(
                                         false, HARDWARE, targetServices, userId);
                             } else {
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
index f088592..66faa31 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
@@ -117,7 +117,7 @@
     @Override
     public void onCheckedChanged(boolean isChecked) {
         setShortcutEnabled(isChecked);
-        if (Flags.a11yQsShortcut()) {
+        if (Flags.migrateEnableShortcuts()) {
             final AccessibilityManager am =
                     getContext().getSystemService(AccessibilityManager.class);
             am.enableShortcutsForTargets(
diff --git a/core/java/com/android/internal/pm/pkg/component/flags/flags.aconfig b/core/java/com/android/internal/pm/pkg/component/flags/flags.aconfig
index 89db1cb..ea9abdb 100644
--- a/core/java/com/android/internal/pm/pkg/component/flags/flags.aconfig
+++ b/core/java/com/android/internal/pm/pkg/component/flags/flags.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.internal.pm.pkg.component.flags"
-container: "system"
 
 flag {
     name: "enable_per_process_use_embedded_dex_attr"
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index e12becd..8c7b360 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -238,6 +238,7 @@
      */
     public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
     public static final int PARSE_APK_IN_APEX = 1 << 9;
+    public static final int PARSE_APEX = 1 << 10;
 
     public static final int PARSE_CHATTY = 1 << 31;
 
@@ -339,6 +340,9 @@
         if ((flags & PARSE_APK_IN_APEX) != 0) {
             liteParseFlags |= PARSE_APK_IN_APEX;
         }
+        if ((flags & PARSE_APEX) != 0) {
+            liteParseFlags |= PARSE_APEX;
+        }
         final ParseResult<PackageLite> liteResult =
                 ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags);
         if (liteResult.isError()) {
@@ -530,7 +534,7 @@
 
         afterParseBaseApplication(pkg);
 
-        final ParseResult<ParsingPackage> result = validateBaseApkTags(input, pkg);
+        final ParseResult<ParsingPackage> result = validateBaseApkTags(input, pkg, flags);
         if (result.isError()) {
             return result;
         }
@@ -1012,10 +1016,11 @@
             }
         }
 
-        return validateBaseApkTags(input, pkg);
+        return validateBaseApkTags(input, pkg, flags);
     }
 
-    private ParseResult<ParsingPackage> validateBaseApkTags(ParseInput input, ParsingPackage pkg) {
+    private ParseResult<ParsingPackage> validateBaseApkTags(ParseInput input, ParsingPackage pkg,
+            int flags) {
         if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) {
             return input.error(
                     INSTALL_PARSE_FAILED_BAD_MANIFEST,
@@ -1047,6 +1052,17 @@
             adjustPackageToBeUnresizeableAndUnpipable(pkg);
         }
 
+        // An Apex package shouldn't have permission declarations
+        final boolean isApex = (flags & PARSE_APEX) != 0;
+        if (android.permission.flags.Flags.ignoreApexPermissions()
+                && isApex && !pkg.getPermissions().isEmpty()) {
+            return input.error(
+                    INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    pkg.getPackageName()
+                            + " is an APEX package and shouldn't declare permissions."
+            );
+        }
+
         return input.success(pkg);
     }
 
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index 9f3ce81..fca4e91 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -53,6 +53,7 @@
 import android.tracing.perfetto.Producer;
 import android.tracing.perfetto.TracingContext;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.LongArray;
 import android.util.Slog;
 import android.util.proto.ProtoInputStream;
@@ -67,6 +68,7 @@
 
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
@@ -166,78 +168,92 @@
         }
 
         mDataSource.trace(ctx -> {
-            final ProtoOutputStream os = ctx.newTracePacket();
+            try {
+                final ProtoOutputStream os = ctx.newTracePacket();
 
-            os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+                os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
 
-            final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
-            while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-                if (pis.getFieldNumber() == (int) MESSAGES) {
-                    final long inMessageToken = pis.start(MESSAGES);
-                    final long outMessagesToken = os.start(MESSAGES);
-
-                    while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-                        switch (pis.getFieldNumber()) {
-                            case (int) MessageData.MESSAGE_ID:
-                                os.write(MessageData.MESSAGE_ID,
-                                        pis.readLong(MessageData.MESSAGE_ID));
-                                break;
-                            case (int) MESSAGE:
-                                os.write(MESSAGE, pis.readString(MESSAGE));
-                                break;
-                            case (int) LEVEL:
-                                os.write(LEVEL, pis.readInt(LEVEL));
-                                break;
-                            case (int) GROUP_ID:
-                                os.write(GROUP_ID, pis.readInt(GROUP_ID));
-                                break;
-                            default:
-                                throw new RuntimeException(
-                                        "Unexpected field id " + pis.getFieldNumber());
-                        }
+                final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
+                while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                    if (pis.getFieldNumber() == (int) MESSAGES) {
+                        writeViewerConfigMessage(pis, os);
                     }
 
-                    pis.end(inMessageToken);
-                    os.end(outMessagesToken);
-                }
-
-                if (pis.getFieldNumber() == (int) GROUPS) {
-                    final long inGroupToken = pis.start(GROUPS);
-                    final long outGroupToken = os.start(GROUPS);
-
-                    while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-                        switch (pis.getFieldNumber()) {
-                            case (int) ID:
-                                int id = pis.readInt(ID);
-                                os.write(ID, id);
-                                break;
-                            case (int) NAME:
-                                String name = pis.readString(NAME);
-                                os.write(NAME, name);
-                                break;
-                            case (int) TAG:
-                                String tag = pis.readString(TAG);
-                                os.write(TAG, tag);
-                                break;
-                            default:
-                                throw new RuntimeException(
-                                        "Unexpected field id " + pis.getFieldNumber());
-                        }
+                    if (pis.getFieldNumber() == (int) GROUPS) {
+                        writeViewerConfigGroup(pis, os);
                     }
-
-                    pis.end(inGroupToken);
-                    os.end(outGroupToken);
                 }
+
+                os.end(outProtologViewerConfigToken);
+
+                ctx.flush();
+            } catch (IOException e) {
+                Log.e(LOG_TAG, "Failed to read ProtoLog viewer config to dump on tracing end", e);
             }
-
-            os.end(outProtologViewerConfigToken);
-
-            ctx.flush();
         });
 
         mDataSource.flush();
     }
 
+    private static void writeViewerConfigGroup(
+            ProtoInputStream pis, ProtoOutputStream os) throws IOException {
+        final long inGroupToken = pis.start(GROUPS);
+        final long outGroupToken = os.start(GROUPS);
+
+        while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pis.getFieldNumber()) {
+                case (int) ID:
+                    int id = pis.readInt(ID);
+                    os.write(ID, id);
+                    break;
+                case (int) NAME:
+                    String name = pis.readString(NAME);
+                    os.write(NAME, name);
+                    break;
+                case (int) TAG:
+                    String tag = pis.readString(TAG);
+                    os.write(TAG, tag);
+                    break;
+                default:
+                    throw new RuntimeException(
+                            "Unexpected field id " + pis.getFieldNumber());
+            }
+        }
+
+        pis.end(inGroupToken);
+        os.end(outGroupToken);
+    }
+
+    private static void writeViewerConfigMessage(
+            ProtoInputStream pis, ProtoOutputStream os) throws IOException {
+        final long inMessageToken = pis.start(MESSAGES);
+        final long outMessagesToken = os.start(MESSAGES);
+
+        while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (pis.getFieldNumber()) {
+                case (int) MessageData.MESSAGE_ID:
+                    os.write(MessageData.MESSAGE_ID,
+                            pis.readLong(MessageData.MESSAGE_ID));
+                    break;
+                case (int) MESSAGE:
+                    os.write(MESSAGE, pis.readString(MESSAGE));
+                    break;
+                case (int) LEVEL:
+                    os.write(LEVEL, pis.readInt(LEVEL));
+                    break;
+                case (int) GROUP_ID:
+                    os.write(GROUP_ID, pis.readInt(GROUP_ID));
+                    break;
+                default:
+                    throw new RuntimeException(
+                            "Unexpected field id " + pis.getFieldNumber());
+            }
+        }
+
+        pis.end(inMessageToken);
+        os.end(outMessagesToken);
+    }
+
     private void logToLogcat(String tag, LogLevel level, long messageHash,
             @Nullable String messageString, Object[] args) {
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "logToLogcat");
@@ -423,7 +439,7 @@
         return sw.toString();
     }
 
-    private int internStacktraceString(TracingContext<ProtoLogDataSource.Instance,
+    private int internStacktraceString(TracingContext<
             ProtoLogDataSource.TlsState,
             ProtoLogDataSource.IncrementalState> ctx,
             String stacktrace) {
@@ -433,9 +449,7 @@
     }
 
     private int internStringArg(
-            TracingContext<ProtoLogDataSource.Instance,
-            ProtoLogDataSource.TlsState,
-            ProtoLogDataSource.IncrementalState> ctx,
+            TracingContext<ProtoLogDataSource.TlsState, ProtoLogDataSource.IncrementalState> ctx,
             String string
     ) {
         final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
@@ -444,9 +458,7 @@
     }
 
     private int internString(
-            TracingContext<ProtoLogDataSource.Instance,
-                ProtoLogDataSource.TlsState,
-                ProtoLogDataSource.IncrementalState> ctx,
+            TracingContext<ProtoLogDataSource.TlsState, ProtoLogDataSource.IncrementalState> ctx,
             Map<String, Integer> internMap,
             long fieldId,
             String string
diff --git a/core/jni/android_tracing_PerfettoDataSource.cpp b/core/jni/android_tracing_PerfettoDataSource.cpp
index 25ff853..5c7b470 100644
--- a/core/jni/android_tracing_PerfettoDataSource.cpp
+++ b/core/jni/android_tracing_PerfettoDataSource.cpp
@@ -45,12 +45,6 @@
 static struct {
     jclass clazz;
     jmethodID init;
-    jmethodID getAndClearAllPendingTracePackets;
-} gTracingContextClassInfo;
-
-static struct {
-    jclass clazz;
-    jmethodID init;
 } gCreateTlsStateArgsClassInfo;
 
 static struct {
@@ -68,32 +62,10 @@
     jobject jobj;
 };
 
-static void traceAllPendingPackets(JNIEnv* env, jobject jCtx, PerfettoDsTracerIterator* ctx) {
-    jobjectArray packets =
-            (jobjectArray)env
-                    ->CallObjectMethod(jCtx,
-                                       gTracingContextClassInfo.getAndClearAllPendingTracePackets);
-    if (env->ExceptionOccurred()) {
-        env->ExceptionDescribe();
-        env->ExceptionClear();
-
-        LOG_ALWAYS_FATAL("Failed to call java context finalize method");
-    }
-
-    int packets_count = env->GetArrayLength(packets);
-    for (int i = 0; i < packets_count; i++) {
-        jbyteArray packet_proto_buffer = (jbyteArray)env->GetObjectArrayElement(packets, i);
-
-        jbyte* raw_proto_buffer = env->GetByteArrayElements(packet_proto_buffer, 0);
-        int buffer_size = env->GetArrayLength(packet_proto_buffer);
-
-        struct PerfettoDsRootTracePacket trace_packet;
-        PerfettoDsTracerPacketBegin(ctx, &trace_packet);
-        PerfettoPbMsgAppendBytes(&trace_packet.msg.msg, (const uint8_t*)raw_proto_buffer,
-                                 buffer_size);
-        PerfettoDsTracerPacketEnd(ctx, &trace_packet);
-    }
-}
+// In a single thread there can be only one trace point active across all data source, so we can use
+// a single global thread_local variable to keep track of the active tracer iterator.
+thread_local static bool gInIteration;
+thread_local static struct PerfettoDsTracerIterator gIterator;
 
 PerfettoDataSource::PerfettoDataSource(JNIEnv* env, jobject javaDataSource,
                                        std::string dataSourceName)
@@ -164,44 +136,89 @@
     return env->NewGlobalRef(incrementalState.get());
 }
 
-void PerfettoDataSource::trace(JNIEnv* env, jobject traceFunction) {
-    PERFETTO_DS_TRACE(dataSource, ctx) {
-        ALOG(LOG_DEBUG, LOG_TAG, "\tin native trace callback function %p", this);
-        TlsState* tls_state =
-                reinterpret_cast<TlsState*>(PerfettoDsGetCustomTls(&dataSource, &ctx));
-        IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(
-                PerfettoDsGetIncrementalState(&dataSource, &ctx));
+bool PerfettoDataSource::TraceIterateBegin() {
+    if (gInIteration) {
+        return false;
+    }
 
-        ALOG(LOG_DEBUG, LOG_TAG, "\t tls_state = %p", tls_state);
-        ALOG(LOG_DEBUG, LOG_TAG, "\t incr_state = %p", incr_state);
+    gIterator = PerfettoDsTraceIterateBegin(&dataSource);
 
-        ALOG(LOG_DEBUG, LOG_TAG, "\t tls_state->jobj = %p", tls_state->jobj);
-        ALOG(LOG_DEBUG, LOG_TAG, "\t incr_state->jobj = %p", incr_state->jobj);
+    if (gIterator.impl.tracer == nullptr) {
+        return false;
+    }
 
-        ScopedLocalRef<jobject> jCtx(env,
-                                     env->NewObject(gTracingContextClassInfo.clazz,
-                                                    gTracingContextClassInfo.init, &ctx,
-                                                    tls_state->jobj, incr_state->jobj));
+    gInIteration = true;
+    return true;
+}
 
-        ALOG(LOG_DEBUG, LOG_TAG, "\t jCtx = %p", jCtx.get());
+bool PerfettoDataSource::TraceIterateNext() {
+    if (!gInIteration) {
+        LOG_ALWAYS_FATAL("Tried calling TraceIterateNext outside of a tracer iteration.");
+        return false;
+    }
 
-        jclass objclass = env->GetObjectClass(traceFunction);
-        jmethodID method =
-                env->GetMethodID(objclass, "trace", "(Landroid/tracing/perfetto/TracingContext;)V");
-        if (method == 0) {
-            LOG_ALWAYS_FATAL("Failed to get method id");
-        }
+    PerfettoDsTraceIterateNext(&dataSource, &gIterator);
 
-        env->ExceptionClear();
+    if (gIterator.impl.tracer == nullptr) {
+        // Reached end of iterator. No more datasource instances.
+        gInIteration = false;
+        return false;
+    }
 
-        env->CallVoidMethod(traceFunction, method, jCtx.get());
-        if (env->ExceptionOccurred()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-            LOG_ALWAYS_FATAL("Failed to call java trace method");
-        }
+    return true;
+}
 
-        traceAllPendingPackets(env, jCtx.get(), &ctx);
+void PerfettoDataSource::TraceIterateBreak() {
+    if (!gInIteration) {
+        return;
+    }
+
+    PerfettoDsTraceIterateBreak(&dataSource, &gIterator);
+    gInIteration = false;
+}
+
+jobject PerfettoDataSource::GetCustomTls() {
+    if (!gInIteration) {
+        LOG_ALWAYS_FATAL("Tried getting CustomTls outside of a tracer iteration.");
+        return nullptr;
+    }
+
+    TlsState* tls_state =
+            reinterpret_cast<TlsState*>(PerfettoDsGetCustomTls(&dataSource, &gIterator));
+
+    return tls_state->jobj;
+}
+
+jobject PerfettoDataSource::GetIncrementalState() {
+    if (!gInIteration) {
+        LOG_ALWAYS_FATAL("Tried getting IncrementalState outside of a tracer iteration.");
+        return nullptr;
+    }
+
+    IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(
+            PerfettoDsGetIncrementalState(&dataSource, &gIterator));
+
+    return incr_state->jobj;
+}
+
+void PerfettoDataSource::WritePackets(JNIEnv* env, jobjectArray packets) {
+    if (!gInIteration) {
+        LOG_ALWAYS_FATAL("Tried writing packets outside of a tracer iteration.");
+        return;
+    }
+
+    int packets_count = env->GetArrayLength(packets);
+    for (int i = 0; i < packets_count; i++) {
+        jbyteArray packet_proto_buffer = (jbyteArray)env->GetObjectArrayElement(packets, i);
+
+        jbyte* raw_proto_buffer = env->GetByteArrayElements(packet_proto_buffer, 0);
+        int buffer_size = env->GetArrayLength(packet_proto_buffer);
+
+        struct PerfettoDsRootTracePacket trace_packet;
+        PerfettoDsTracerPacketBegin(&gIterator, &trace_packet);
+        PerfettoPbMsgAppendBytes(&trace_packet.msg.msg, (const uint8_t*)raw_proto_buffer,
+                                 buffer_size);
+        PerfettoDsTracerPacketEnd(&gIterator, &trace_packet);
     }
 }
 
@@ -218,9 +235,7 @@
 
 jlong nativeCreate(JNIEnv* env, jclass clazz, jobject javaDataSource, jstring name) {
     const char* nativeString = env->GetStringUTFChars(name, 0);
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeCreate(%p, %s)", javaDataSource, nativeString);
     PerfettoDataSource* dataSource = new PerfettoDataSource(env, javaDataSource, nativeString);
-    ALOG(LOG_DEBUG, LOG_TAG, "\tdatasource* = %p", dataSource);
     env->ReleaseStringUTFChars(name, nativeString);
 
     dataSource->incStrong((void*)nativeCreate);
@@ -229,39 +244,27 @@
 }
 
 void nativeDestroy(void* ptr) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeCreate(%p)", ptr);
     PerfettoDataSource* dataSource = reinterpret_cast<PerfettoDataSource*>(ptr);
     dataSource->decStrong((void*)nativeCreate);
 }
 
 static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeGetFinalizer()");
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&nativeDestroy));
 }
 
-void nativeTrace(JNIEnv* env, jclass clazz, jlong dataSourcePtr, jobject traceFunctionInterface) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeTrace(%p)", (void*)dataSourcePtr);
-    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
-
-    datasource->trace(env, traceFunctionInterface);
-}
-
-void nativeFlush(JNIEnv* env, jclass clazz, jobject jCtx, jlong ctxPtr) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeFlush(%p, %p)", jCtx, (void*)ctxPtr);
-    auto* ctx = reinterpret_cast<struct PerfettoDsTracerIterator*>(ctxPtr);
-    traceAllPendingPackets(env, jCtx, ctx);
-    PerfettoDsTracerFlush(ctx, nullptr, nullptr);
+void nativeFlush(JNIEnv* env, jclass clazz, jlong ds_ptr, jobjectArray packets) {
+    ALOG(LOG_DEBUG, LOG_TAG, "nativeFlush(%p)", (void*)ds_ptr);
+    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(ds_ptr);
+    datasource->WritePackets(env, packets);
 }
 
 void nativeFlushAll(JNIEnv* env, jclass clazz, jlong ptr) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeFlushAll(%p)", (void*)ptr);
     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(ptr);
     datasource->flushAll();
 }
 
 void nativeRegisterDataSource(JNIEnv* env, jclass clazz, jlong datasource_ptr,
                               int buffer_exhausted_policy) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeRegisterDataSource(%p)", (void*)datasource_ptr);
     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(datasource_ptr);
 
     struct PerfettoDsParams params = PerfettoDsParamsDefault();
@@ -283,10 +286,6 @@
 
         auto* datasource_instance =
                 new PerfettoDataSourceInstance(env, java_data_source_instance.get(), inst_id);
-
-        ALOG(LOG_DEBUG, LOG_TAG, "on_setup_cb ds=%p, ds_instance=%p", datasource,
-             datasource_instance);
-
         return static_cast<void*>(datasource_instance);
     };
 
@@ -299,9 +298,6 @@
         jobject java_tls_state = datasource->createTlsStateGlobalRef(env, inst_id);
 
         auto* tls_state = new TlsState(java_tls_state);
-
-        ALOG(LOG_DEBUG, LOG_TAG, "on_create_tls_cb ds=%p, tsl_state=%p", datasource, tls_state);
-
         return static_cast<void*>(tls_state);
     };
 
@@ -310,8 +306,6 @@
 
         TlsState* tls_state = reinterpret_cast<TlsState*>(ptr);
 
-        ALOG(LOG_DEBUG, LOG_TAG, "on_delete_tls_cb %p", tls_state);
-
         env->DeleteGlobalRef(tls_state->jobj);
         delete tls_state;
     };
@@ -324,9 +318,6 @@
         jobject java_incr_state = datasource->createIncrementalStateGlobalRef(env, inst_id);
 
         auto* incr_state = new IncrementalState(java_incr_state);
-
-        ALOG(LOG_DEBUG, LOG_TAG, "on_create_incr_cb ds=%p, incr_state=%p", datasource, incr_state);
-
         return static_cast<void*>(incr_state);
     };
 
@@ -335,8 +326,6 @@
 
         IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(ptr);
 
-        ALOG(LOG_DEBUG, LOG_TAG, "on_delete_incr_cb incr_state=%p", incr_state);
-
         env->DeleteGlobalRef(incr_state->jobj);
         delete incr_state;
     };
@@ -346,9 +335,6 @@
         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
 
         auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
-
-        ALOG(LOG_DEBUG, LOG_TAG, "on_start_cb ds_instance=%p", datasource_instance);
-
         datasource_instance->onStart(env);
     };
 
@@ -357,9 +343,6 @@
         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
 
         auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
-
-        ALOG(LOG_DEBUG, LOG_TAG, "on_flush_cb ds_instance=%p", datasource_instance);
-
         datasource_instance->onFlush(env);
     };
 
@@ -368,9 +351,6 @@
         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
 
         auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
-
-        ALOG(LOG_DEBUG, LOG_TAG, "on_stop_cb ds_instance=%p", datasource_instance);
-
         datasource_instance->onStop(env);
     };
 
@@ -378,18 +358,14 @@
                               void* inst_ctx) -> void {
         auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
 
-        ALOG(LOG_DEBUG, LOG_TAG, "on_destroy_cb ds_instance=%p", datasource_instance);
-
         delete datasource_instance;
     };
 
     PerfettoDsRegister(&datasource->dataSource, datasource->dataSourceName.c_str(), params);
 }
 
-jobject nativeGetPerfettoInstanceLocked(JNIEnv* env, jclass clazz, jlong dataSourcePtr,
+jobject nativeGetPerfettoInstanceLocked(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr,
                                         PerfettoDsInstanceIndex instance_idx) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeGetPerfettoInstanceLocked ds=%p, idx=%d", (void*)dataSourcePtr,
-         instance_idx);
     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
     auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(
             PerfettoDsImplGetInstanceLocked(datasource->dataSource.impl, instance_idx));
@@ -401,24 +377,44 @@
         return nullptr;
     }
 
-    ALOG(LOG_DEBUG, LOG_TAG, "\tnativeGetPerfettoInstanceLocked got lock ds=%p, idx=%d",
-         (void*)dataSourcePtr, instance_idx);
     return datasource_instance->GetJavaDataSourceInstance();
 }
 
-void nativeReleasePerfettoInstanceLocked(JNIEnv* env, jclass clazz, jlong dataSourcePtr,
+void nativeReleasePerfettoInstanceLocked(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr,
                                          PerfettoDsInstanceIndex instance_idx) {
-    ALOG(LOG_DEBUG, LOG_TAG, "nativeReleasePerfettoInstanceLocked got lock ds=%p, idx=%d",
-         (void*)dataSourcePtr, instance_idx);
     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
     PerfettoDsImplReleaseInstanceLocked(datasource->dataSource.impl, instance_idx);
 }
 
+bool nativePerfettoDsTraceIterateBegin(jlong dataSourcePtr) {
+    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
+    return datasource->TraceIterateBegin();
+}
+
+bool nativePerfettoDsTraceIterateNext(jlong dataSourcePtr) {
+    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
+    return datasource->TraceIterateNext();
+}
+
+void nativePerfettoDsTraceIterateBreak(jlong dataSourcePtr) {
+    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
+    return datasource->TraceIterateBreak();
+}
+
+jobject nativeGetCustomTls(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
+    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
+    return datasource->GetCustomTls();
+}
+
+jobject nativeGetIncrementalState(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
+    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
+    return datasource->GetIncrementalState();
+}
+
 const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
         {"nativeCreate", "(Landroid/tracing/perfetto/DataSource;Ljava/lang/String;)J",
          (void*)nativeCreate},
-        {"nativeTrace", "(JLandroid/tracing/perfetto/TraceFunction;)V", (void*)nativeTrace},
         {"nativeFlushAll", "(J)V", (void*)nativeFlushAll},
         {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer},
         {"nativeRegisterDataSource", "(JI)V", (void*)nativeRegisterDataSource},
@@ -426,11 +422,16 @@
          (void*)nativeGetPerfettoInstanceLocked},
         {"nativeReleasePerfettoInstanceLocked", "(JI)V",
          (void*)nativeReleasePerfettoInstanceLocked},
-};
+
+        {"nativePerfettoDsTraceIterateBegin", "(J)Z", (void*)nativePerfettoDsTraceIterateBegin},
+        {"nativePerfettoDsTraceIterateNext", "(J)Z", (void*)nativePerfettoDsTraceIterateNext},
+        {"nativePerfettoDsTraceIterateBreak", "(J)V", (void*)nativePerfettoDsTraceIterateBreak}};
 
 const JNINativeMethod gMethodsTracingContext[] = {
         /* name, signature, funcPtr */
-        {"nativeFlush", "(Landroid/tracing/perfetto/TracingContext;J)V", (void*)nativeFlush},
+        {"nativeFlush", "(J[[B)V", (void*)nativeFlush},
+        {"nativeGetCustomTls", "(J)Ljava/lang/Object;", (void*)nativeGetCustomTls},
+        {"nativeGetIncrementalState", "(J)Ljava/lang/Object;", (void*)nativeGetIncrementalState},
 };
 
 int register_android_tracing_PerfettoDataSource(JNIEnv* env) {
@@ -461,14 +462,6 @@
                              "(Landroid/tracing/perfetto/CreateIncrementalStateArgs;)Ljava/lang/"
                              "Object;");
 
-    clazz = env->FindClass("android/tracing/perfetto/TracingContext");
-    gTracingContextClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
-    gTracingContextClassInfo.init = env->GetMethodID(gTracingContextClassInfo.clazz, "<init>",
-                                                     "(JLjava/lang/Object;Ljava/lang/Object;)V");
-    gTracingContextClassInfo.getAndClearAllPendingTracePackets =
-            env->GetMethodID(gTracingContextClassInfo.clazz, "getAndClearAllPendingTracePackets",
-                             "()[[B");
-
     clazz = env->FindClass("android/tracing/perfetto/CreateTlsStateArgs");
     gCreateTlsStateArgsClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
     gCreateTlsStateArgsClassInfo.init =
diff --git a/core/jni/android_tracing_PerfettoDataSource.h b/core/jni/android_tracing_PerfettoDataSource.h
index 906d9f5..209de29 100644
--- a/core/jni/android_tracing_PerfettoDataSource.h
+++ b/core/jni/android_tracing_PerfettoDataSource.h
@@ -46,7 +46,15 @@
 
     jobject createTlsStateGlobalRef(JNIEnv* env, PerfettoDsInstanceIndex inst_id);
     jobject createIncrementalStateGlobalRef(JNIEnv* env, PerfettoDsInstanceIndex inst_id);
-    void trace(JNIEnv* env, jobject trace_function);
+
+    bool TraceIterateBegin();
+    bool TraceIterateNext();
+    void TraceIterateBreak();
+    void WritePackets(JNIEnv* env, jobjectArray packets);
+
+    jobject GetCustomTls();
+    jobject GetIncrementalState();
+
     void flushAll();
 
 private:
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 4e61ff2..3489cac 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -4,7 +4,6 @@
 cinek@google.com
 dsandler@android.com
 dsandler@google.com
-dupin@google.com
 hackbod@android.com
 hackbod@google.com
 ilyamaty@google.com
@@ -49,7 +48,7 @@
 # Wear
 per-file res/*-watch/* = file:/WEAR_OWNERS
 
-# Peformance
+# Performance
 per-file res/values/config.xml = file:/PERFORMANCE_OWNERS
 per-file res/values/symbols.xml = file:/PERFORMANCE_OWNERS
 
@@ -63,3 +62,11 @@
 
 # TV Input Framework
 per-file res/values/config_tv_external_input_logging.xml = file:/services/core/java/com/android/server/tv/OWNERS
+
+# SysUi Color Team
+per-file res/values/colors.xml = arteiro@google.com
+per-file res/values/attrs.xml = arteiro@google.com
+per-file res/values/styles.xml = arteiro@google.com
+per-file res/values/symbols.xml = arteiro@google.com
+per-file res/values/themes_device_defaults.xml = arteiro@google.com
+per-file res/values/styles_material.xml = arteiro@google.com
\ No newline at end of file
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index c8625b9..9bb72d9 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -28,7 +28,7 @@
          standard SMS rate. The user is warned when the destination phone number matches the
          "pattern" or "premium" regexes, and does not match the "free" or "standard" regexes. -->
 
-    <!-- Harmonised European Short Codes are 6 digit numbers starting with 116 (free helplines).
+    <!-- Harmonised European Short Codes are 7 digit numbers starting with 116 (free helplines).
          Premium patterns include short codes from: http://aonebill.com/coverage&tariffs
          and http://mobilcent.com/info-worldwide.asp and extracted from:
          http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
@@ -39,8 +39,8 @@
     <!-- Albania: 5 digits, known short codes listed -->
     <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
 
-    <!-- Argentina: 5 digits, known short codes listed -->
-    <shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077|78887" />
+    <!-- Argentina: 6 digits, known short codes listed -->
+    <shortcode country="ar" pattern="\\d{1,6}" free="11711|28291|44077|78887|191289|39010" />
 
     <!-- Armenia: 3-5 digits, emergency numbers 10[123] -->
     <shortcode country="am" pattern="\\d{3,5}" premium="11[2456]1|3024" free="10[123]|71522|71512|71502" />
@@ -67,7 +67,7 @@
     <shortcode country="bh" pattern="\\d{1,5}" free="81181|85999" />
 
     <!-- Brazil: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000" />
+    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000|2652" />
 
     <!-- Belarus: 4 digits -->
     <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
@@ -163,7 +163,7 @@
     <shortcode country="in" pattern="\\d{1,5}" free="59336|53969" />
 
     <!-- Indonesia: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363|93457" />
+    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363|93457|99265" />
 
     <!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:
          http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
@@ -172,6 +172,9 @@
     <!-- Israel: 1-5 digits, known premium codes listed -->
     <shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477|6681" />
 
+    <!-- Iran: 4-6 digits, known premium codes listed -->
+    <shortcode country="ir" pattern="\\d{4,6}" free="700791|700792" />
+
     <!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
          https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
     <shortcode country="it" pattern="\\d{5}" premium="44[0-4]\\d{2}|47[0-4]\\d{2}|48[0-4]\\d{2}|44[5-9]\\d{4}|47[5-9]\\d{4}|48[5-9]\\d{4}|455\\d{2}|499\\d{2}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" />
@@ -219,11 +222,11 @@
     <!-- Mozambique: 1-5 digits (standard system default, not country specific) -->
     <shortcode country="mz" pattern="\\d{1,5}" free="1714" />
 
-    <!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="mx" pattern="\\d{4,6}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346" />
+    <!-- Mexico: 4-7 digits (not confirmed), known premium codes listed -->
+    <shortcode country="mx" pattern="\\d{4,7}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346|3030303" />
 
     <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
-    <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
+    <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668|66966" />
 
     <!-- Namibia: 1-5 digits (standard system default, not country specific) -->
     <shortcode country="na" pattern="\\d{1,5}" free="40005" />
@@ -255,6 +258,9 @@
     <!-- Palestine: 5 digits, known premium codes listed -->
     <shortcode country="ps" pattern="\\d{1,5}" free="37477|6681" />
 
+    <!-- Paraguay: 6 digits, known premium codes listed -->
+    <shortcode country="py" pattern="\\d{6}" free="191289" />
+
     <!-- Poland: 4-5 digits (not confirmed), known premium codes listed, plus EU -->
     <shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}|8012|80921" />
 
@@ -275,7 +281,7 @@
     <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/>
 
     <!-- Rwanda: 4 digits -->
-    <shortcode country="rw" pattern="\\d{4}" free="5060" />
+    <shortcode country="rw" pattern="\\d{4}" free="5060|5061" />
 
     <!-- Saudi Arabia -->
     <shortcode country="sa" pattern="\\d{1,5}" free="8145" />
@@ -309,7 +315,10 @@
     <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
 
     <!-- Tanzania: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="tz" pattern="\\d{1,5}" free="15046|15234" />
+    <shortcode country="tz" pattern="\\d{1,5}" free="15046|15234|15324" />
+
+    <!-- Tunisia: 5 digits, known premium codes listed -->
+    <shortcode country="tn" pattern="\\d{5}" free="85799" />
 
     <!-- Turkey -->
     <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493|3193" />
@@ -324,8 +333,11 @@
          visual voicemail code for T-Mobile: 122 -->
     <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611|96831" />
 
-    <!--Uruguay : 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="uy" pattern="\\d{1,5}" free="55002" />
+    <!--Uruguay : 1-6 digits (standard system default, not country specific) -->
+    <shortcode country="uy" pattern="\\d{1,6}" free="55002|191289" />
+
+    <!-- Venezuela: 1-6 digits (standard system default, not country specific) -->
+    <shortcode country="ve" pattern="\\d{1,6}" free="538352" />
 
     <!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
     <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055|8079" />
@@ -336,6 +348,9 @@
     <!-- South Africa -->
     <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056|33009" />
 
+    <!-- Yemen -->
+    <shortcode country="ye" pattern="\\d{1,4}" free="5081" />
+
     <!-- Zimbabwe -->
     <shortcode country="zw" pattern="\\d{1,5}" free="33679" />
 
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 5fab1a0..d560ef2 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -420,7 +420,7 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testClickingDisableButtonInDialog_shouldClearShortcutId() throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
         configureValidShortcutService();
@@ -443,7 +443,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testClickingDisableButtonInDialog_shouldClearShortcutId_old() throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
         configureValidShortcutService();
@@ -467,7 +467,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE)
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void turnOffVolumeShortcutForAlwaysOnA11yService_shouldTurnOffA11yService()
             throws Exception {
         configureApplicationTargetSdkVersion(Build.VERSION_CODES.R);
@@ -480,7 +480,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE)
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void turnOffVolumeShortcutForAlwaysOnA11yService_hasOtherTypesShortcut_shouldNotTurnOffA11yService()
             throws Exception {
         configureApplicationTargetSdkVersion(Build.VERSION_CODES.R);
@@ -527,7 +527,7 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testTurnOnDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOn()
             throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -551,7 +551,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testTurnOnDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOn_old()
             throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -574,7 +574,7 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testTurnOffDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOff()
             throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -598,7 +598,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void testTurnOffDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOff_old()
             throws Exception {
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java
index a14d8e0..9cac312 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java
@@ -117,7 +117,7 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_true_callA11yManagerToUpdateShortcuts() throws Exception {
         mSut.onCheckedChanged(true);
 
@@ -130,7 +130,7 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_false_callA11yManagerToUpdateShortcuts() throws Exception {
         mSut.onCheckedChanged(false);
         verify(mAccessibilityManagerService).enableShortcutsForTargets(
@@ -142,7 +142,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_turnOnShortcut_hasOtherShortcut_serviceKeepsOn() {
         enableA11yService(/* enable= */ true);
         addShortcutForA11yService(
@@ -155,7 +155,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_turnOnShortcut_noOtherShortcut_shouldTurnOnService() {
         enableA11yService(/* enable= */ false);
         addShortcutForA11yService(
@@ -168,7 +168,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_turnOffShortcut_hasOtherShortcut_serviceKeepsOn() {
         enableA11yService(/* enable= */ true);
         addShortcutForA11yService(
@@ -181,7 +181,7 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
+    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)
     public void onCheckedChanged_turnOffShortcut_noOtherShortcut_shouldTurnOffService() {
         enableA11yService(/* enable= */ true);
         addShortcutForA11yService(
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index efbbfc2..24aea37 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -229,4 +229,24 @@
                     "Keystore error while trying to get apps affected by SID.");
         }
     }
+
+    /**
+    * Deletes all keys in all KeyMint devices.
+    * Called by RecoverySystem before rebooting to recovery in order to delete all KeyMint keys,
+    * including synthetic password protector keys (used by LockSettingsService), as well as keys
+    * protecting DE and metadata encryption keys (used by vold). This ensures that FBE-encrypted
+    * data is unrecoverable even if the data wipe in recovery is interrupted or skipped.
+    */
+    public static void deleteAllKeys() throws KeyStoreException {
+        StrictMode.noteDiskWrite();
+        try {
+            getService().deleteAllKeys();
+        } catch (RemoteException | NullPointerException e) {
+            throw new KeyStoreException(SYSTEM_ERROR,
+                    "Failure to connect to Keystore while trying to delete all keys.");
+        } catch (ServiceSpecificException e) {
+            throw new KeyStoreException(e.errorCode,
+                    "Keystore error while trying to delete all keys.");
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
index ef7478c..c0ff192 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml
@@ -22,14 +22,15 @@
     android:layout_height="wrap_content"
     android:gravity="center_horizontal">
 
-    <ImageButton
+    <com.android.wm.shell.windowdecor.HandleImageButton
         android:id="@+id/caption_handle"
         android:layout_width="@dimen/desktop_mode_fullscreen_decor_caption_width"
         android:layout_height="@dimen/desktop_mode_fullscreen_decor_caption_height"
         android:paddingVertical="16dp"
+        android:paddingHorizontal="10dp"
         android:contentDescription="@string/handle_text"
         android:src="@drawable/decor_handle_dark"
         tools:tint="@color/desktop_mode_caption_handle_bar_dark"
         android:scaleType="fitXY"
-        android:background="?android:selectableItemBackground"/>
+        android:background="@android:color/transparent"/>
 </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 39dd4d3..6d5bf62 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -423,8 +423,9 @@
     <!-- Height of desktop mode caption for fullscreen tasks. -->
     <dimen name="desktop_mode_fullscreen_decor_caption_height">36dp</dimen>
 
-    <!-- Width of desktop mode caption for fullscreen tasks. -->
-    <dimen name="desktop_mode_fullscreen_decor_caption_width">128dp</dimen>
+    <!-- Width of desktop mode caption for fullscreen tasks.
+        80 dp for handle + 20 dp for room to grow on the sides when hovered. -->
+    <dimen name="desktop_mode_fullscreen_decor_caption_width">100dp</dimen>
 
     <!-- Required empty space to be visible for partially offscreen tasks. -->
     <dimen name="freeform_required_visible_empty_space_in_header">48dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 97bf8f7..73b2656 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -32,6 +32,7 @@
 import android.app.IActivityTaskManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.hardware.input.InputManager;
 import android.net.Uri;
@@ -71,6 +72,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
 import com.android.wm.shell.shared.annotations.ShellMainThread;
+import com.android.wm.shell.sysui.ConfigurationChangeListener;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -81,7 +83,8 @@
 /**
  * Controls the window animation run when a user initiates a back gesture.
  */
-public class BackAnimationController implements RemoteCallable<BackAnimationController> {
+public class BackAnimationController implements RemoteCallable<BackAnimationController>,
+        ConfigurationChangeListener {
     private static final String TAG = "ShellBackPreview";
     private static final int SETTING_VALUE_OFF = 0;
     private static final int SETTING_VALUE_ON = 1;
@@ -248,6 +251,7 @@
         mShellController.addExternalInterface(KEY_EXTRA_SHELL_BACK_ANIMATION,
                 this::createExternalInterface, this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
+        mShellController.addConfigurationChangeListener(this);
     }
 
     private void setupAnimationDeveloperSettingsObserver(
@@ -297,6 +301,11 @@
     private final BackAnimationImpl mBackAnimation = new BackAnimationImpl();
 
     @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        mShellBackAnimationRegistry.onConfigurationChanged(newConfig);
+    }
+
+    @Override
     public Context getContext() {
         return mContext;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index c6d4620..112ed09 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -68,7 +68,7 @@
 
     private val backAnimRect = Rect()
 
-    private val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
+    private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
 
     private val backAnimationRunner = BackAnimationRunner(
         Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY
@@ -94,6 +94,10 @@
     private var scrimLayer: SurfaceControl? = null
     private var maxScrimAlpha: Float = 0f
 
+    override fun onConfigurationChanged(newConfiguration: Configuration) {
+        cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
+    }
+
     override fun getRunner() = backAnimationRunner
 
     private fun startBackAnimation(backMotionEvent: BackMotionEvent) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index 987001d..c34f30d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -29,6 +29,7 @@
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Matrix;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -80,7 +81,7 @@
     private static final int POST_ANIMATION_DURATION_MS = 500;
 
     private final Rect mStartTaskRect = new Rect();
-    private final float mCornerRadius;
+    private float mCornerRadius;
 
     // The closing window properties.
     private final Rect mClosingStartRect = new Rect();
@@ -120,6 +121,11 @@
         mContext = context;
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
+    }
+
     private static float mapRange(float value, float min, float max) {
         return min + (value * (max - min));
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
index e33aa75..838dab4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
@@ -29,6 +29,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -63,7 +64,7 @@
 public class CustomizeActivityAnimation extends ShellBackAnimation {
     private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
     private final BackAnimationRunner mBackAnimationRunner;
-    private final float mCornerRadius;
+    private float mCornerRadius;
     private final SurfaceControl.Transaction mTransaction;
     private final BackAnimationBackground mBackground;
     private RemoteAnimationTarget mEnteringTarget;
@@ -88,6 +89,7 @@
     final Transformation mTransformation = new Transformation();
 
     private final Choreographer mChoreographer;
+    private final Context mContext;
 
     @Inject
     public CustomizeActivityAnimation(Context context, BackAnimationBackground background) {
@@ -108,6 +110,12 @@
                 .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY));
         mTransaction = transaction == null ? new SurfaceControl.Transaction() : transaction;
         mChoreographer = choreographer != null ? choreographer : Choreographer.getInstance();
+        mContext = context;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
     }
 
     private float getLatestProgress() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java
index dc65919..8a0daaa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimation.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.back;
 
+import android.content.res.Configuration;
 import android.window.BackNavigationInfo;
 
 import javax.inject.Qualifier;
@@ -48,4 +49,8 @@
     public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo) {
         return false;
     }
+
+    void onConfigurationChanged(Configuration newConfig) {
+
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
index 26d2097..00daddc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.res.Configuration;
 import android.util.Log;
 import android.util.SparseArray;
 import android.window.BackNavigationInfo;
@@ -29,6 +30,7 @@
     private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>();
     private final ShellBackAnimation mDefaultCrossActivityAnimation;
     private final ShellBackAnimation mCustomizeActivityAnimation;
+    private final ShellBackAnimation mCrossTaskAnimation;
 
     public ShellBackAnimationRegistry(
             @ShellBackAnimation.CrossActivity @Nullable ShellBackAnimation crossActivityAnimation,
@@ -57,6 +59,7 @@
 
         mDefaultCrossActivityAnimation = crossActivityAnimation;
         mCustomizeActivityAnimation = customizeActivityAnimation;
+        mCrossTaskAnimation = crossTaskAnimation;
 
         // TODO(b/236760237): register dialog close animation when it's completed.
     }
@@ -125,6 +128,12 @@
                 BackNavigationInfo.TYPE_CROSS_ACTIVITY, mDefaultCrossActivityAnimation.getRunner());
     }
 
+    void onConfigurationChanged(Configuration newConfig) {
+        mCustomizeActivityAnimation.onConfigurationChanged(newConfig);
+        mDefaultCrossActivityAnimation.onConfigurationChanged(newConfig);
+        mCrossTaskAnimation.onConfigurationChanged(newConfig);
+    }
+
     BackAnimationRunner getAnimationRunnerAndInit(BackNavigationInfo backNavigationInfo) {
         int type = backNavigationInfo.getType();
         // Initiate customized cross-activity animation, or fall back to cross activity animation
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index e210ea7..58942ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -1354,6 +1354,13 @@
                     "setTaskListener"
             ) { _ -> listener?.let { remoteListener.register(it) } ?: remoteListener.unregister() }
         }
+
+        override fun moveToDesktop(taskId: Int) {
+            ExecutorUtils.executeRemoteCallWithTaskPermission(
+                controller,
+                "moveToDesktop"
+            ) { c -> c.moveToDesktop(taskId) }
+        }
     }
 
     companion object {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index 6bdaf1e..fa43522 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -45,4 +45,7 @@
 
     /** Set listener that will receive callbacks about updates to desktop tasks */
     oneway void setTaskListener(IDesktopTaskListener listener);
+
+    /** Move a task with given `taskId` to desktop */
+    void moveToDesktop(int taskId);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 5762197..6aad4e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -18,9 +18,14 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.graphics.Rect;
+import android.os.Bundle;
+import android.window.RemoteTransition;
 
+import com.android.internal.logging.InstanceId;
+import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
 import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
 import com.android.wm.shell.shared.annotations.ExternalThread;
 
@@ -72,6 +77,12 @@
         }
     }
 
+    /** Launches a pair of tasks into splitscreen */
+    void startTasks(int taskId1, @Nullable Bundle options1, int taskId2,
+            @Nullable Bundle options2, @SplitPosition int splitPosition,
+            @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition,
+            InstanceId instanceId);
+
     /** Registers listener that gets split screen callback. */
     void registerSplitScreenListener(@NonNull SplitScreenListener listener,
             @NonNull Executor executor);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 088bb48..547457b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -506,6 +506,15 @@
         return mStageCoordinator.getActivateSplitPosition(taskInfo);
     }
 
+    /** Start two tasks in parallel as a splitscreen pair. */
+    public void startTasks(int taskId1, @Nullable Bundle options1, int taskId2,
+            @Nullable Bundle options2, @SplitPosition int splitPosition,
+            @PersistentSnapPosition int snapPosition,
+            @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+        mStageCoordinator.startTasks(taskId1, options1, taskId2, options2, splitPosition,
+                snapPosition, remoteTransition, instanceId);
+    }
+
     /**
      * Move a task to split select
      * @param taskInfo the task being moved to split select
@@ -1120,6 +1129,15 @@
         };
 
         @Override
+        public void startTasks(int taskId1, @Nullable Bundle options1, int taskId2,
+                @Nullable Bundle options2, int splitPosition, int snapPosition,
+                @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+            mMainExecutor.execute(() -> SplitScreenController.this.startTasks(
+                    taskId1, options1, taskId2, options2, splitPosition, snapPosition,
+                    remoteTransition, instanceId));
+        }
+
+        @Override
         public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
             if (mExecutors.containsKey(listener)) return;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index c26604a..7c2ba45 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -293,7 +293,13 @@
     @Override
     public void onFoldStateChanged(boolean isFolded) {
         if (isFolded) {
+            // Reset unfold animation finished flag on folding, so it could be used next time
+            // when we unfold the device as an indication that animation hasn't finished yet
             mAnimationFinished = false;
+
+            // If we are currently animating unfold animation we should finish it because
+            // the animation might not start and finish as the device was folded
+            finishTransitionIfNeeded();
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index d0879434..b865d94 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.windowingModeToString;
+import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_UP;
 
@@ -752,7 +753,9 @@
         final int action = ev.getActionMasked();
         // The comparison against ACTION_UP is needed for the cancel drag to desktop case.
         handle.setHovered(inHandle && action != ACTION_UP);
-        handle.setPressed(inHandle && action == ACTION_DOWN);
+        // We want handle to remain pressed if the pointer moves outside of it during a drag.
+        handle.setPressed((inHandle && action == ACTION_DOWN)
+                || (handle.isPressed() && action != ACTION_UP && action != ACTION_CANCEL));
         if (isHandleMenuActive()) {
             mHandleMenu.checkMotionEvent(ev);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt
new file mode 100644
index 0000000..b21c3f5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.wm.shell.windowdecor
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageButton
+
+/**
+ * [ImageButton] for the handle at the top of fullscreen apps. Has custom hover
+ * and press handling to grow the handle on hover enter and shrink the handle on
+ * hover exit and press.
+ */
+class HandleImageButton (context: Context?, attrs: AttributeSet?) :
+    ImageButton(context, attrs) {
+    private val handleAnimator = ValueAnimator()
+
+    override fun onHoverChanged(hovered: Boolean) {
+        super.onHoverChanged(hovered)
+        if (hovered) {
+            animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_HOVER_ENTER_SCALE)
+        } else {
+            if (!isPressed) {
+                animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_DEFAULT_SCALE)
+            }
+        }
+    }
+
+    override fun setPressed(pressed: Boolean) {
+        if (isPressed != pressed) {
+            super.setPressed(pressed)
+            if (pressed) {
+                animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_PRESS_DOWN_SCALE)
+            } else {
+                animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_DEFAULT_SCALE)
+            }
+        }
+    }
+
+    private fun animateHandle(duration: Long, endScale: Float) {
+        if (handleAnimator.isRunning) {
+            handleAnimator.cancel()
+        }
+        handleAnimator.duration = duration
+        handleAnimator.setFloatValues(scaleX, endScale)
+        handleAnimator.addUpdateListener { animator ->
+            scaleX = animator.animatedValue as Float
+        }
+        handleAnimator.start()
+    }
+
+    companion object {
+        /** The duration of animations related to hover state. **/
+        private const val HANDLE_HOVER_ANIM_DURATION = 300L
+        /** The duration of animations related to pressed state. **/
+        private const val HANDLE_PRESS_ANIM_DURATION = 200L
+        /** Ending scale for hover enter. **/
+        private const val HANDLE_HOVER_ENTER_SCALE = 1.2f
+        /** Ending scale for press down. **/
+        private const val HANDLE_PRESS_DOWN_SCALE = 0.85f
+        /** Default scale for handle. **/
+        private const val HANDLE_DEFAULT_SCALE = 1f
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt
index 2fda3ea..7898567 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt
@@ -21,7 +21,7 @@
 import android.widget.ImageButton
 
 /**
- * A custom [ImageButton] that intentionally does not handle hover events.
+ * A custom [ImageButton] for buttons inside handle menu that intentionally doesn't handle hovers.
  * This is due to the hover events being handled by [DesktopModeWindowDecorViewModel]
  * in order to take the status bar layer into account. Handling it in both classes results in a
  * flicker when the hover moves from outside to inside status bar layer.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 2ff1ddd..9c623bd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -120,6 +120,8 @@
     private TestableContentResolver mContentResolver;
     private TestableLooper mTestableLooper;
 
+    private CrossActivityBackAnimation mCrossActivityBackAnimation;
+    private CrossTaskBackAnimation mCrossTaskBackAnimation;
     private ShellBackAnimationRegistry mShellBackAnimationRegistry;
 
     @Before
@@ -133,11 +135,11 @@
                 ANIMATION_ENABLED);
         mTestableLooper = TestableLooper.get(this);
         mShellInit = spy(new ShellInit(mShellExecutor));
+        mCrossActivityBackAnimation = new CrossActivityBackAnimation(mContext, mAnimationBackground,
+                mRootTaskDisplayAreaOrganizer);
+        mCrossTaskBackAnimation = new CrossTaskBackAnimation(mContext, mAnimationBackground);
         mShellBackAnimationRegistry =
-                new ShellBackAnimationRegistry(
-                        new CrossActivityBackAnimation(
-                                mContext, mAnimationBackground, mRootTaskDisplayAreaOrganizer),
-                        new CrossTaskBackAnimation(mContext, mAnimationBackground),
+                new ShellBackAnimationRegistry(mCrossActivityBackAnimation, mCrossTaskBackAnimation,
                         /* dialogCloseAnimation= */ null,
                         new CustomizeActivityAnimation(mContext, mAnimationBackground),
                         /* defaultBackToHomeAnimation= */ null);
@@ -576,16 +578,14 @@
 
     @Test
     public void testBackToActivity() throws RemoteException {
-        final CrossActivityBackAnimation animation = new CrossActivityBackAnimation(
-                mContext, mAnimationBackground, mRootTaskDisplayAreaOrganizer);
-        verifySystemBackBehavior(BackNavigationInfo.TYPE_CROSS_ACTIVITY, animation.getRunner());
+        verifySystemBackBehavior(BackNavigationInfo.TYPE_CROSS_ACTIVITY,
+                mCrossActivityBackAnimation.getRunner());
     }
 
     @Test
     public void testBackToTask() throws RemoteException {
-        final CrossTaskBackAnimation animation = new CrossTaskBackAnimation(mContext,
-                mAnimationBackground);
-        verifySystemBackBehavior(BackNavigationInfo.TYPE_CROSS_TASK, animation.getRunner());
+        verifySystemBackBehavior(BackNavigationInfo.TYPE_CROSS_TASK,
+                mCrossTaskBackAnimation.getRunner());
     }
 
     private void verifySystemBackBehavior(int type, BackAnimationRunner animation)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index c5e229f..acc0bce 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -298,6 +298,32 @@
     }
 
     @Test
+    public void fold_animationInProgress_finishesTransition() {
+        TransitionRequestInfo requestInfo = createUnfoldTransitionRequestInfo();
+        TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class);
+
+        // Unfold
+        mShellUnfoldProgressProvider.onFoldStateChanged(/* isFolded= */ false);
+        mUnfoldTransitionHandler.handleRequest(mTransition, requestInfo);
+        mUnfoldTransitionHandler.startAnimation(
+                mTransition,
+                mock(TransitionInfo.class),
+                mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
+                finishCallback
+        );
+
+        // Start animation but don't finish it
+        mShellUnfoldProgressProvider.onStateChangeStarted();
+        mShellUnfoldProgressProvider.onStateChangeProgress(0.5f);
+
+        // Fold
+        mShellUnfoldProgressProvider.onFoldStateChanged(/* isFolded= */ true);
+
+        verify(finishCallback).onTransitionFinished(any());
+    }
+
+    @Test
     public void mergeAnimation_eatsDisplayOnlyTransitions() {
         TransitionRequestInfo requestInfo = createUnfoldTransitionRequestInfo();
         mUnfoldTransitionHandler.handleRequest(mTransition, requestInfo);
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 2904dfe..708b011 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -442,14 +442,17 @@
         }
 
         // TODO: maybe we want to get rid of the WCG check if overlay properties just works?
-        const bool canUseFp16 = DeviceInfo::get()->isSupportFp16ForHdr() ||
-                                DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType;
+        bool canUseFp16 = DeviceInfo::get()->isSupportFp16ForHdr() ||
+                DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType;
 
-        if (canUseFp16) {
-            if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
-                colorMode = ColorMode::Default;
-            } else {
-                config = mEglConfigF16;
+        if (colorMode == ColorMode::Hdr) {
+            if (canUseFp16 && !DeviceInfo::get()->isSupportRgba10101010ForHdr()) {
+                if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
+                    // If the driver doesn't support fp16 then fallback to 8-bit
+                    canUseFp16 = false;
+                } else {
+                    config = mEglConfigF16;
+                }
             }
         }
 
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index b8b03b6..19e59a7 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -1,5 +1,4 @@
 package: "android.location.flags"
-container: "system"
 
 flag {
     name: "new_geocoder"
diff --git a/media/java/android/media/flags/editing.aconfig b/media/java/android/media/flags/editing.aconfig
index bf6ec96..5bf1b4e 100644
--- a/media/java/android/media/flags/editing.aconfig
+++ b/media/java/android/media/flags/editing.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.media.editing.flags"
-container: "system"
 
 flag {
   name: "add_media_metrics_editing"
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 91c4f11..8d6982e 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.media.flags"
-container: "system"
 
 flag {
     name: "enable_rlp_callbacks_in_media_router2"
diff --git a/media/java/android/media/flags/projection.aconfig b/media/java/android/media/flags/projection.aconfig
index 9a9a073..b165809 100644
--- a/media/java/android/media/flags/projection.aconfig
+++ b/media/java/android/media/flags/projection.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.media.projection.flags"
-container: "system"
 
 # Project link: https://gantry.corp.google.com/projects/android_platform_window_surfaces/changes
 
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index 97971e1..1731e5e 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -1,5 +1,4 @@
 package: "android.media.tv.flags"
-container: "system"
 
 flag {
     name: "broadcast_visibility_types"
diff --git a/media/jni/playback_flags.aconfig b/media/jni/playback_flags.aconfig
index 9d927ec..2bb0ec5 100644
--- a/media/jni/playback_flags.aconfig
+++ b/media/jni/playback_flags.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.media.playback.flags"
-container: "system"
 
 flag {
   name: "mediametadataretriever_default_rgba8888"
diff --git a/nfc/TEST_MAPPING b/nfc/TEST_MAPPING
index 5b5ea37..49c778d 100644
--- a/nfc/TEST_MAPPING
+++ b/nfc/TEST_MAPPING
@@ -5,6 +5,9 @@
     },
     {
       "name": "CtsNfcTestCases"
+    },
+    {
+      "name": "CtsNdefTestCases"
     }
   ]
 }
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 73b29db..778f07c 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.nfc"
-container: "system"
 
 flag {
     name: "enable_nfc_mainline"
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index 0af1080..e8e24f4 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -40,6 +40,7 @@
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:gravity">center</item>
+        <item name="android:textDirection">locale</item>
         <item name="android:layout_marginLeft">14dp</item>
         <item name="android:layout_marginRight">14dp</item>
         <item name="android:textSize">20sp</item>
@@ -53,6 +54,7 @@
         <item name="android:layout_marginTop">18dp</item>
         <item name="android:layout_marginLeft">18dp</item>
         <item name="android:layout_marginRight">18dp</item>
+        <item name="android:textDirection">locale</item>
         <item name="android:textSize">14sp</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig
index 35d7393..8627eac 100644
--- a/packages/CrashRecovery/aconfig/flags.aconfig
+++ b/packages/CrashRecovery/aconfig/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.crashrecovery.flags"
-container: "system"
 
 flag {
     name: "recoverability_detection"
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index 8891b50..75a8bdf 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -39,15 +39,15 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.BackgroundThread;
-import android.util.LongArrayQueue;
 import android.util.Slog;
 import android.util.Xml;
+import android.utils.BackgroundThread;
+import android.utils.LongArrayQueue;
+import android.utils.XmlUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index 271d552..f86eb61 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -31,7 +31,6 @@
 import android.crashrecovery.flags.Flags;
 import android.os.Build;
 import android.os.Environment;
-import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.RecoverySystem;
 import android.os.SystemClock;
@@ -44,10 +43,11 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.utils.ArrayUtils;
+import android.utils.FileUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.server.PackageWatchdog.FailureReasons;
 import com.android.server.PackageWatchdog.PackageHealthObserver;
 import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
diff --git a/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java
new file mode 100644
index 0000000..fa4d6af
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java
@@ -0,0 +1,115 @@
+/*
+ * 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 android.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.File;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java
+ *
+ * @hide
+ */
+public class ArrayUtils {
+    private ArrayUtils() { /* cannot be instantiated */ }
+    public static final File[] EMPTY_FILE = new File[0];
+
+
+    /**
+     * Return first index of {@code value} in {@code array}, or {@code -1} if
+     * not found.
+     */
+    public static <T> int indexOf(@Nullable T[] array, T value) {
+        if (array == null) return -1;
+        for (int i = 0; i < array.length; i++) {
+            if (Objects.equals(array[i], value)) return i;
+        }
+        return -1;
+    }
+
+    /** @hide */
+    public static @NonNull File[] defeatNullable(@Nullable File[] val) {
+        return (val != null) ? val : EMPTY_FILE;
+    }
+
+    /**
+     * Checks if given array is null or has zero elements.
+     */
+    public static boolean isEmpty(@Nullable int[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
+     * True if the byte array is null or has length 0.
+     */
+    public static boolean isEmpty(@Nullable byte[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
+     * Converts from List of bytes to byte array
+     * @param list
+     * @return byte[]
+     */
+    public static byte[] toPrimitive(List<byte[]> list) {
+        if (list.size() == 0) {
+            return new byte[0];
+        }
+        int byteLen = list.get(0).length;
+        byte[] array = new byte[list.size() * byteLen];
+        for (int i = 0; i < list.size(); i++) {
+            for (int j = 0; j < list.get(i).length; j++) {
+                array[i * byteLen + j] = list.get(i)[j];
+            }
+        }
+        return array;
+    }
+
+    /**
+     * Adds value to given array if not already present, providing set-like
+     * behavior.
+     */
+    public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
+        return appendInt(cur, val, false);
+    }
+
+    /**
+     * Adds value to given array.
+     */
+    public static @NonNull int[] appendInt(@Nullable int[] cur, int val,
+            boolean allowDuplicates) {
+        if (cur == null) {
+            return new int[] { val };
+        }
+        final int n = cur.length;
+        if (!allowDuplicates) {
+            for (int i = 0; i < n; i++) {
+                if (cur[i] == val) {
+                    return cur;
+                }
+            }
+        }
+        int[] ret = new int[n + 1];
+        System.arraycopy(cur, 0, ret, 0, n);
+        ret[n] = val;
+        return ret;
+    }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java
similarity index 99%
rename from packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
rename to packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java
index a6ae68f..afcf689 100644
--- a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
+++ b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.util;
+package android.utils;
 
 import android.annotation.NonNull;
 import android.os.Handler;
diff --git a/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java
new file mode 100644
index 0000000..e4923bf
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java
@@ -0,0 +1,128 @@
+/*
+ * 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 android.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Bits and pieces copied from hidden API of android.os.FileUtils.
+ *
+ * @hide
+ */
+public class FileUtils {
+    /**
+     * Read a text file into a String, optionally limiting the length.
+     *
+     * @param file     to read (will not seek, so things like /proc files are OK)
+     * @param max      length (positive for head, negative of tail, 0 for no limit)
+     * @param ellipsis to add of the file was truncated (can be null)
+     * @return the contents of the file, possibly truncated
+     * @throws IOException if something goes wrong reading the file
+     * @hide
+     */
+    public static @Nullable String readTextFile(@Nullable File file, @Nullable int max,
+            @Nullable String ellipsis) throws IOException {
+        InputStream input = new FileInputStream(file);
+        // wrapping a BufferedInputStream around it because when reading /proc with unbuffered
+        // input stream, bytes read not equal to buffer size is not necessarily the correct
+        // indication for EOF; but it is true for BufferedInputStream due to its implementation.
+        BufferedInputStream bis = new BufferedInputStream(input);
+        try {
+            long size = file.length();
+            if (max > 0 || (size > 0 && max == 0)) {  // "head" mode: read the first N bytes
+                if (size > 0 && (max == 0 || size < max)) max = (int) size;
+                byte[] data = new byte[max + 1];
+                int length = bis.read(data);
+                if (length <= 0) return "";
+                if (length <= max) return new String(data, 0, length);
+                if (ellipsis == null) return new String(data, 0, max);
+                return new String(data, 0, max) + ellipsis;
+            } else if (max < 0) {  // "tail" mode: keep the last N
+                int len;
+                boolean rolled = false;
+                byte[] last = null;
+                byte[] data = null;
+                do {
+                    if (last != null) rolled = true;
+                    byte[] tmp = last;
+                    last = data;
+                    data = tmp;
+                    if (data == null) data = new byte[-max];
+                    len = bis.read(data);
+                } while (len == data.length);
+
+                if (last == null && len <= 0) return "";
+                if (last == null) return new String(data, 0, len);
+                if (len > 0) {
+                    rolled = true;
+                    System.arraycopy(last, len, last, 0, last.length - len);
+                    System.arraycopy(data, 0, last, last.length - len, len);
+                }
+                if (ellipsis == null || !rolled) return new String(last);
+                return ellipsis + new String(last);
+            } else {  // "cat" mode: size unknown, read it all in streaming fashion
+                ByteArrayOutputStream contents = new ByteArrayOutputStream();
+                int len;
+                byte[] data = new byte[1024];
+                do {
+                    len = bis.read(data);
+                    if (len > 0) contents.write(data, 0, len);
+                } while (len == data.length);
+                return contents.toString();
+            }
+        } finally {
+            bis.close();
+            input.close();
+        }
+    }
+
+    /**
+     * Perform an fsync on the given FileOutputStream. The stream at this
+     * point must be flushed but not yet closed.
+     *
+     * @hide
+     */
+    public static boolean sync(FileOutputStream stream) {
+        try {
+            if (stream != null) {
+                stream.getFD().sync();
+            }
+            return true;
+        } catch (IOException e) {
+        }
+        return false;
+    }
+
+    /**
+     * List the files in the directory or return empty file.
+     *
+     * @hide
+     */
+    public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {
+        return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles())
+            : ArrayUtils.EMPTY_FILE;
+    }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java
similarity index 98%
rename from packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
rename to packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java
index 948ebcca..fdb15e2 100644
--- a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
+++ b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.util;
+package android.utils;
 
 import android.annotation.NonNull;
 import android.os.Handler;
diff --git a/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java
new file mode 100644
index 0000000..5cdc253
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java
@@ -0,0 +1,188 @@
+/*
+ * 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 android.utils;
+
+import libcore.util.EmptyArray;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Copied from frameworks/base/core/java/android/util/LongArrayQueue.java
+ *
+ * @hide
+ */
+public class LongArrayQueue {
+
+    private long[] mValues;
+    private int mSize;
+    private int mHead;
+    private int mTail;
+
+    private long[] newUnpaddedLongArray(int num) {
+        return new long[num];
+    }
+    /**
+     * Initializes a queue with the given starting capacity.
+     *
+     * @param initialCapacity the capacity.
+     */
+    public LongArrayQueue(int initialCapacity) {
+        if (initialCapacity == 0) {
+            mValues = EmptyArray.LONG;
+        } else {
+            mValues = newUnpaddedLongArray(initialCapacity);
+        }
+        mSize = 0;
+        mHead = mTail = 0;
+    }
+
+    /**
+     * Initializes a queue with default starting capacity.
+     */
+    public LongArrayQueue() {
+        this(16);
+    }
+
+    /** @hide */
+    public static int growSize(int currentSize) {
+        return currentSize <= 4 ? 8 : currentSize * 2;
+    }
+
+    private void grow() {
+        if (mSize < mValues.length) {
+            throw new IllegalStateException("Queue not full yet!");
+        }
+        final int newSize = growSize(mSize);
+        final long[] newArray = newUnpaddedLongArray(newSize);
+        final int r = mValues.length - mHead; // Number of elements on and to the right of head.
+        System.arraycopy(mValues, mHead, newArray, 0, r);
+        System.arraycopy(mValues, 0, newArray, r, mHead);
+        mValues = newArray;
+        mHead = 0;
+        mTail = mSize;
+    }
+
+    /**
+     * Returns the number of elements in the queue.
+     */
+    public int size() {
+        return mSize;
+    }
+
+    /**
+     * Removes all elements from this queue.
+     */
+    public void clear() {
+        mSize = 0;
+        mHead = mTail = 0;
+    }
+
+    /**
+     * Adds a value to the tail of the queue.
+     *
+     * @param value the value to be added.
+     */
+    public void addLast(long value) {
+        if (mSize == mValues.length) {
+            grow();
+        }
+        mValues[mTail] = value;
+        mTail = (mTail + 1) % mValues.length;
+        mSize++;
+    }
+
+    /**
+     * Removes an element from the head of the queue.
+     *
+     * @return the element at the head of the queue.
+     * @throws NoSuchElementException if the queue is empty.
+     */
+    public long removeFirst() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        final long ret = mValues[mHead];
+        mHead = (mHead + 1) % mValues.length;
+        mSize--;
+        return ret;
+    }
+
+    /**
+     * Returns the element at the given position from the head of the queue, where 0 represents the
+     * head of the queue.
+     *
+     * @param position the position from the head of the queue.
+     * @return the element found at the given position.
+     * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or
+     *                                   {@code position} >= {@link #size()}
+     */
+    public long get(int position) {
+        if (position < 0 || position >= mSize) {
+            throw new IndexOutOfBoundsException("Index " + position
+                + " not valid for a queue of size " + mSize);
+        }
+        final int index = (mHead + position) % mValues.length;
+        return mValues[index];
+    }
+
+    /**
+     * Returns the element at the head of the queue, without removing it.
+     *
+     * @return the element at the head of the queue.
+     * @throws NoSuchElementException if the queue is empty
+     */
+    public long peekFirst() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        return mValues[mHead];
+    }
+
+    /**
+     * Returns the element at the tail of the queue.
+     *
+     * @return the element at the tail of the queue.
+     * @throws NoSuchElementException if the queue is empty.
+     */
+    public long peekLast() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1;
+        return mValues[index];
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        if (mSize <= 0) {
+            return "{}";
+        }
+
+        final StringBuilder buffer = new StringBuilder(mSize * 64);
+        buffer.append('{');
+        buffer.append(get(0));
+        for (int i = 1; i < mSize; i++) {
+            buffer.append(", ");
+            buffer.append(get(i));
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java
new file mode 100644
index 0000000..dbbef61
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java
@@ -0,0 +1,118 @@
+/*
+ * 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 android.utils;
+
+import android.annotation.NonNull;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import com.android.modules.utils.TypedXmlPullParser;
+
+import libcore.util.XmlObjectFactory;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Copied over partly from frameworks/base/core/java/com/android/internal/util/XmlUtils.java
+ *
+ * @hide
+ */
+public class XmlUtils {
+
+    private static final String STRING_ARRAY_SEPARATOR = ":";
+
+    /** @hide */
+    public static final void beginDocument(XmlPullParser parser, String firstElementName)
+            throws XmlPullParserException, IOException {
+        int type;
+        while ((type = parser.next()) != parser.START_TAG
+            && type != parser.END_DOCUMENT) {
+            // Do nothing
+        }
+
+        if (type != parser.START_TAG) {
+            throw new XmlPullParserException("No start tag found");
+        }
+
+        if (!parser.getName().equals(firstElementName)) {
+            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
+                + ", expected " + firstElementName);
+        }
+    }
+
+    /** @hide */
+    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
+            throws IOException, XmlPullParserException {
+        for (;;) {
+            int type = parser.next();
+            if (type == XmlPullParser.END_DOCUMENT
+                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
+                return false;
+            }
+            if (type == XmlPullParser.START_TAG
+                    && parser.getDepth() == outerDepth + 1) {
+                return true;
+            }
+        }
+    }
+
+    private static XmlPullParser newPullParser() {
+        try {
+            XmlPullParser parser = XmlObjectFactory.newXmlPullParser();
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+            return parser;
+        } catch (XmlPullParserException e) {
+            throw new AssertionError();
+        }
+    }
+
+    /** @hide */
+    public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
+            throws IOException {
+        final byte[] magic = new byte[4];
+        if (in instanceof FileInputStream) {
+            try {
+                Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+        } else {
+            if (!in.markSupported()) {
+                in = new BufferedInputStream(in);
+            }
+            in.mark(8);
+            in.read(magic);
+            in.reset();
+        }
+
+        final TypedXmlPullParser xml;
+        xml = (TypedXmlPullParser) newPullParser();
+        try {
+            xml.setInput(in, "UTF_8");
+        } catch (XmlPullParserException e) {
+            throw new IOException(e);
+        }
+        return xml;
+    }
+}
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index b408c15..9c8ec3b 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -142,7 +142,7 @@
                     isDefaultIconPreferredAsSingleProvider =
                             credentialEntry.isDefaultIconPreferredAsSingleProvider,
                     affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
-                    biometricRequest = predetermineAndValidateBiometricFlow(it,
+                    biometricRequest = retrieveEntryBiometricRequest(it,
                         CREDENTIAL_ENTRY_PREFIX),
                 )
                 )
@@ -172,7 +172,7 @@
                     isDefaultIconPreferredAsSingleProvider =
                             credentialEntry.isDefaultIconPreferredAsSingleProvider,
                     affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
-                    biometricRequest = predetermineAndValidateBiometricFlow(it,
+                    biometricRequest = retrieveEntryBiometricRequest(it,
                         CREDENTIAL_ENTRY_PREFIX),
                 )
                 )
@@ -201,7 +201,7 @@
                     isDefaultIconPreferredAsSingleProvider =
                             credentialEntry.isDefaultIconPreferredAsSingleProvider,
                     affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
-                    biometricRequest = predetermineAndValidateBiometricFlow(it,
+                    biometricRequest = retrieveEntryBiometricRequest(it,
                         CREDENTIAL_ENTRY_PREFIX),
                 )
                 )
@@ -216,7 +216,7 @@
 }
 
 /**
- * This validates if this is a biometric flow or not, and if it is, this returns the expected
+ * This validates if the entry calling this method contains biometric info, and if so, returns a
  * [BiometricRequestInfo]. Namely, the biometric flow must have at least the
  * ALLOWED_AUTHENTICATORS bit passed from Jetpack.
  * Note that the required values, such as the provider info's icon or display name, or the entries
@@ -230,7 +230,7 @@
  * // TODO(b/326243754) : Presently, due to dependencies, the opId bit is parsed but is never
  * // expected to be used. When it is added, it should be lightly validated.
  */
-fun predetermineAndValidateBiometricFlow(
+fun retrieveEntryBiometricRequest(
     entry: Entry,
     hintPrefix: String,
 ): BiometricRequestInfo? {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index a039753..888777e 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -30,6 +30,8 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.lifecycle.ViewModel
+import com.android.credentialmanager.common.BiometricFlowType
+import com.android.credentialmanager.common.BiometricPromptState
 import com.android.credentialmanager.common.BiometricResult
 import com.android.credentialmanager.common.BiometricState
 import com.android.credentialmanager.model.EntryInfo
@@ -40,7 +42,7 @@
 import com.android.credentialmanager.createflow.ActiveEntry
 import com.android.credentialmanager.createflow.CreateCredentialUiState
 import com.android.credentialmanager.createflow.CreateScreenState
-import com.android.credentialmanager.createflow.findBiometricFlowEntry
+import com.android.credentialmanager.createflow.isBiometricFlow
 import com.android.credentialmanager.getflow.GetCredentialUiState
 import com.android.credentialmanager.getflow.GetScreenState
 import com.android.credentialmanager.logging.LifecycleEvent
@@ -303,13 +305,23 @@
     }
 
     fun createFlowOnEntrySelectedFromMoreOptionScreen(activeEntry: ActiveEntry) {
+        val isBiometricFlow = isBiometricFlow(activeEntry = activeEntry, isAutoSelectFlow = false)
+        if (isBiometricFlow) {
+            // This atomically ensures that the only edge case that *restarts* the biometric flow
+            // doesn't risk a configuration change bug on the more options page during create.
+            // Namely, it's atomic in that it happens only on a tap, and it is not possible to
+            // reproduce a tap and a rotation at the same time. However, even if it were, it would
+            // just be an alternate way to jump back into the biometric selection flow after this
+            // reset, and thus, the state machine is maintained.
+            onBiometricPromptStateChange(BiometricPromptState.INACTIVE)
+        }
         uiState = uiState.copy(
             createCredentialUiState = uiState.createCredentialUiState?.copy(
                 currentScreenState =
                 // An autoselect flow never makes it to the more options screen
-                if (findBiometricFlowEntry(activeEntry = activeEntry,
-                        isAutoSelectFlow = false) != null) CreateScreenState.BIOMETRIC_SELECTION
-                else if (
+                if (isBiometricFlow) {
+                    CreateScreenState.BIOMETRIC_SELECTION
+                } else if (
                     uiState.createCredentialUiState?.requestDisplayInfo?.userSetDefaultProviderIds
                         ?.contains(activeEntry.activeProvider.id) ?: true ||
                     !(uiState.createCredentialUiState?.foundCandidateFromUserDefaultProvider
@@ -375,6 +387,46 @@
         }
     }
 
+    /**************************************************************************/
+    /*****                     Biometric Flow Callbacks                   *****/
+    /**************************************************************************/
+
+    /**
+     * This allows falling back from the biometric prompt screen to the normal get flow by applying
+     * a reset to all necessary states involved in the fallback.
+     */
+    fun fallbackFromBiometricToNormalFlow(biometricFlowType: BiometricFlowType) {
+        onBiometricPromptStateChange(BiometricPromptState.INACTIVE)
+        when (biometricFlowType) {
+            BiometricFlowType.GET -> getFlowOnBackToPrimarySelectionScreen()
+            BiometricFlowType.CREATE -> createFlowOnUseOnceSelected()
+        }
+    }
+
+    /**
+     * This method can be used to change the [BiometricPromptState] according to the necessity.
+     * For example, if resetting, one might use [BiometricPromptState.INACTIVE], but if the flow
+     * has just launched, to avoid configuration errors, one can use
+     * [BiometricPromptState.PENDING].
+     */
+    fun onBiometricPromptStateChange(biometricPromptState: BiometricPromptState) {
+        uiState = uiState.copy(
+            biometricState = uiState.biometricState.copy(
+                biometricStatus = biometricPromptState
+            )
+        )
+    }
+
+    /**
+     * This returns the present biometric state.
+     */
+    fun getBiometricPromptState(): BiometricPromptState =
+        uiState.biometricState.biometricStatus
+
+    /**************************************************************************/
+    /*****                     Misc. Callbacks/Logs                       *****/
+    /**************************************************************************/
+
     @Composable
     fun logUiEvent(uiEventEnum: UiEventEnum) {
         this.uiMetrics.log(uiEventEnum, credManRepo.requestInfo?.packageName)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 358ebfa..c477f30 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -53,8 +53,9 @@
 import org.json.JSONObject
 import android.credentials.flags.Flags
 import com.android.credentialmanager.createflow.isBiometricFlow
+import com.android.credentialmanager.createflow.isFlowAutoSelectable
 import com.android.credentialmanager.getflow.TopBrandingContent
-import com.android.credentialmanager.ktx.predetermineAndValidateBiometricFlow
+import com.android.credentialmanager.ktx.retrieveEntryBiometricRequest
 import java.time.Instant
 
 fun getAppLabel(
@@ -431,7 +432,12 @@
                 remoteEntryProvider = remoteEntryProvider,
             )
             val isBiometricFlow = if (activeEntry == null) false else isBiometricFlow(activeEntry,
-                sortedCreateOptionsPairs, requestDisplayInfo)
+                isFlowAutoSelectable(
+                    requestDisplayInfo = requestDisplayInfo,
+                    activeEntry = activeEntry,
+                    sortedCreateOptionsPairs = sortedCreateOptionsPairs
+                )
+            )
             val initialScreenState = toCreateScreenState(
                 createOptionSize = createOptionsPairs.size,
                 remoteEntry = remoteEntry,
@@ -514,7 +520,7 @@
                         it.hasHint("androidx.credentials.provider.createEntry.SLICE_HINT_AUTO_" +
                             "SELECT_ALLOWED")
                     }?.text == "true",
-                    biometricRequest = predetermineAndValidateBiometricFlow(it,
+                    biometricRequest = retrieveEntryBiometricRequest(it,
                         CREATE_ENTRY_PREFIX),
                 )
                 )
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricFlowType.kt
similarity index 95%
rename from packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
rename to packages/CredentialManager/src/com/android/credentialmanager/common/BiometricFlowType.kt
index f6140f5..263cfd5 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricFlowType.kt
@@ -16,7 +16,7 @@
 
 package com.android.credentialmanager.common
 
-enum class FlowType {
+enum class BiometricFlowType {
     GET,
     CREATE
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt
index fa17735..be3e043 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt
@@ -59,7 +59,7 @@
  * ).
  *
  * The above are examples; the credential type can change depending on scenario.
- * // TODO(b/326243891) : Finalize once all the strings and create flow is iterated to completion
+ * // TODO(b/333445112) : Finalize once all the strings and create flow is iterated to completion
  */
 data class BiometricDisplayInfo(
     val providerIcon: Bitmap,
@@ -75,7 +75,8 @@
  * additional states that may improve the flow.
  */
 data class BiometricState(
-    val biometricResult: BiometricResult? = null
+    val biometricResult: BiometricResult? = null,
+    val biometricStatus: BiometricPromptState = BiometricPromptState.INACTIVE
 )
 
 /**
@@ -104,58 +105,115 @@
 )
 
 /**
- * This will handle the logic for integrating credential manager with the biometric prompt for the
- * single account biometric experience. This simultaneously handles both the get and create flows,
- * by retrieving all the data from credential manager, and properly parsing that data into the
- * biometric prompt.
+ * This is the entry point to start the integrated biometric prompt for 'get' flows. It captures
+ * information specific to the get flow, along with required shared callbacks and more general
+ * info across both flows, such as the tapped [EntryInfo] or [sendDataToProvider].
  */
-fun runBiometricFlow(
+fun runBiometricFlowForGet(
     biometricEntry: EntryInfo,
     context: Context,
     openMoreOptionsPage: () -> Unit,
     sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit,
     onCancelFlowAndFinish: () -> Unit,
     onIllegalStateAndFinish: (String) -> Unit,
+    getBiometricPromptState: () -> BiometricPromptState,
+    onBiometricPromptStateChange: (BiometricPromptState) -> Unit,
+    onBiometricFailureFallback: (BiometricFlowType) -> Unit,
     getRequestDisplayInfo: RequestDisplayInfo? = null,
     getProviderInfoList: List<ProviderInfo>? = null,
     getProviderDisplayInfo: ProviderDisplayInfo? = null,
-    onBiometricFailureFallback: () -> Unit,
+) {
+    if (getBiometricPromptState() != BiometricPromptState.INACTIVE) {
+        // Screen is already up, do not re-launch
+        return
+    }
+    onBiometricPromptStateChange(BiometricPromptState.PENDING)
+    val biometricDisplayInfo = validateAndRetrieveBiometricGetDisplayInfo(
+        getRequestDisplayInfo,
+        getProviderInfoList,
+        getProviderDisplayInfo,
+        context, biometricEntry
+    )
+
+    if (biometricDisplayInfo == null) {
+        onBiometricFailureFallback(BiometricFlowType.GET)
+        return
+    }
+
+    val callback: BiometricPrompt.AuthenticationCallback =
+        setupBiometricAuthenticationCallback(sendDataToProvider, biometricEntry,
+            onCancelFlowAndFinish, onIllegalStateAndFinish, onBiometricPromptStateChange)
+
+    Log.d(TAG, "The BiometricPrompt API call begins.")
+    runBiometricFlow(context, biometricDisplayInfo, callback, openMoreOptionsPage,
+        onBiometricFailureFallback, BiometricFlowType.GET)
+}
+
+/**
+ * This is the entry point to start the integrated biometric prompt for 'create' flows. It captures
+ * information specific to the create flow, along with required shared callbacks and more general
+ * info across both flows, such as the tapped [EntryInfo] or [sendDataToProvider].
+ */
+fun runBiometricFlowForCreate(
+    biometricEntry: EntryInfo,
+    context: Context,
+    openMoreOptionsPage: () -> Unit,
+    sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit,
+    onCancelFlowAndFinish: () -> Unit,
+    onIllegalStateAndFinish: (String) -> Unit,
+    getBiometricPromptState: () -> BiometricPromptState,
+    onBiometricPromptStateChange: (BiometricPromptState) -> Unit,
+    onBiometricFailureFallback: (BiometricFlowType) -> Unit,
     createRequestDisplayInfo: com.android.credentialmanager.createflow
     .RequestDisplayInfo? = null,
     createProviderInfo: EnabledProviderInfo? = null,
 ) {
-    // TODO(b/330396089) : Add rotation configuration fix with state machine
-    var biometricDisplayInfo: BiometricDisplayInfo? = null
-    var flowType = FlowType.GET
-    if (getRequestDisplayInfo != null) {
-        biometricDisplayInfo = validateAndRetrieveBiometricGetDisplayInfo(getRequestDisplayInfo,
-            getProviderInfoList,
-            getProviderDisplayInfo,
-            context, biometricEntry)
-    } else if (createRequestDisplayInfo != null) {
-        flowType = FlowType.CREATE
-        biometricDisplayInfo = validateAndRetrieveBiometricCreateDisplayInfo(
-            createRequestDisplayInfo,
-            createProviderInfo,
-            context, biometricEntry)
+    if (getBiometricPromptState() != BiometricPromptState.INACTIVE) {
+        // Screen is already up, do not re-launch
+        return
     }
+    onBiometricPromptStateChange(BiometricPromptState.PENDING)
+    val biometricDisplayInfo = validateAndRetrieveBiometricCreateDisplayInfo(
+        createRequestDisplayInfo,
+        createProviderInfo,
+        context, biometricEntry
+    )
 
     if (biometricDisplayInfo == null) {
-        onBiometricFailureFallback()
+        onBiometricFailureFallback(BiometricFlowType.CREATE)
         return
     }
 
-    val biometricPrompt = setupBiometricPrompt(context, biometricDisplayInfo, openMoreOptionsPage,
-        biometricDisplayInfo.biometricRequestInfo.allowedAuthenticators, flowType)
-
     val callback: BiometricPrompt.AuthenticationCallback =
         setupBiometricAuthenticationCallback(sendDataToProvider, biometricEntry,
-            onCancelFlowAndFinish, onIllegalStateAndFinish)
+            onCancelFlowAndFinish, onIllegalStateAndFinish, onBiometricPromptStateChange)
+
+    Log.d(TAG, "The BiometricPrompt API call begins.")
+    runBiometricFlow(context, biometricDisplayInfo, callback, openMoreOptionsPage,
+        onBiometricFailureFallback, BiometricFlowType.CREATE)
+}
+
+/**
+ * This will handle the logic for integrating credential manager with the biometric prompt for the
+ * single account biometric experience. This simultaneously handles both the get and create flows,
+ * by retrieving all the data from credential manager, and properly parsing that data into the
+ * biometric prompt.
+ */
+private fun runBiometricFlow(
+    context: Context,
+    biometricDisplayInfo: BiometricDisplayInfo,
+    callback: BiometricPrompt.AuthenticationCallback,
+    openMoreOptionsPage: () -> Unit,
+    onBiometricFailureFallback: (BiometricFlowType) -> Unit,
+    biometricFlowType: BiometricFlowType
+) {
+    val biometricPrompt = setupBiometricPrompt(context, biometricDisplayInfo, openMoreOptionsPage,
+        biometricDisplayInfo.biometricRequestInfo, biometricFlowType)
 
     val cancellationSignal = CancellationSignal()
     cancellationSignal.setOnCancelListener {
         Log.d(TAG, "Your cancellation signal was called.")
-        // TODO(b/326243754) : Migrate towards passing along the developer cancellation signal
+        // TODO(b/333445112) : Migrate towards passing along the developer cancellation signal
         // or validate the necessity for this
     }
 
@@ -165,27 +223,28 @@
         biometricPrompt.authenticate(cancellationSignal, executor, callback)
     } catch (e: IllegalArgumentException) {
         Log.w(TAG, "Calling the biometric prompt API failed with: /n${e.localizedMessage}\n")
-        onBiometricFailureFallback()
+        onBiometricFailureFallback(biometricFlowType)
     }
 }
 
 /**
  * Sets up the biometric prompt with the UI specific bits.
- * // TODO(b/326243754) : Pass in opId once dependency is confirmed via CryptoObject
+ * // TODO(b/333445112) : Pass in opId once dependency is confirmed via CryptoObject
  */
 private fun setupBiometricPrompt(
     context: Context,
     biometricDisplayInfo: BiometricDisplayInfo,
     openMoreOptionsPage: () -> Unit,
-    requestAllowedAuthenticators: Int,
-    flowType: FlowType,
+    biometricRequestInfo: BiometricRequestInfo,
+    biometricFlowType: BiometricFlowType,
 ): BiometricPrompt {
-    val finalAuthenticators = removeDeviceCredential(requestAllowedAuthenticators)
+    val finalAuthenticators = removeDeviceCredential(biometricRequestInfo.allowedAuthenticators)
 
     val biometricPrompt = BiometricPrompt.Builder(context)
         .setTitle(biometricDisplayInfo.displayTitleText)
-        // TODO(b/326243754) : Migrate to using new methods recently aligned upon
-        .setNegativeButton(context.getString(if (flowType == FlowType.GET) R.string
+        // TODO(b/333445112) : Migrate to using new methods and strings recently aligned upon
+        .setNegativeButton(context.getString(if (biometricFlowType == BiometricFlowType.GET)
+            R.string
                 .dropdown_presentation_more_sign_in_options_text else R.string.string_more_options),
             getMainExecutor(context)) { _, _ ->
             openMoreOptionsPage()
@@ -200,7 +259,7 @@
     return biometricPrompt
 }
 
-// TODO(b/326243754) : Remove after larger level alignments made on fallback negative button
+// TODO(b/333445112) : Remove after larger level alignments made on fallback negative button
 // For the time being, we do not support the pin fallback until UX is decided.
 private fun removeDeviceCredential(requestAllowedAuthenticators: Int): Int {
     var finalAuthenticators = requestAllowedAuthenticators
@@ -230,16 +289,18 @@
     selectedEntry: EntryInfo,
     onCancelFlowAndFinish: () -> Unit,
     onIllegalStateAndFinish: (String) -> Unit,
+    onBiometricPromptStateChange: (BiometricPromptState) -> Unit
 ): BiometricPrompt.AuthenticationCallback {
     val callback: BiometricPrompt.AuthenticationCallback =
         object : BiometricPrompt.AuthenticationCallback() {
-            // TODO(b/326243754) : Validate remaining callbacks
+            // TODO(b/333445772) : Validate remaining callbacks
             override fun onAuthenticationSucceeded(
                 authResult: BiometricPrompt.AuthenticationResult?
             ) {
                 super.onAuthenticationSucceeded(authResult)
                 try {
                     if (authResult != null) {
+                        onBiometricPromptStateChange(BiometricPromptState.COMPLETE)
                         sendDataToProvider(selectedEntry, authResult)
                     } else {
                         onIllegalStateAndFinish("The biometric flow succeeded but unexpectedly " +
@@ -254,26 +315,24 @@
             override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence?) {
                 super.onAuthenticationHelp(helpCode, helpString)
                 Log.d(TAG, "Authentication help discovered: $helpCode and $helpString")
-                // TODO(b/326243754) : Decide on strategy with provider (a simple log probably
-                // suffices here)
             }
 
             override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
                 super.onAuthenticationError(errorCode, errString)
                 Log.d(TAG, "Authentication error-ed out: $errorCode and $errString")
+                onBiometricPromptStateChange(BiometricPromptState.COMPLETE)
                 if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED) {
                     // Note that because the biometric prompt is imbued directly
                     // into the selector, parity applies to the selector's cancellation instead
                     // of the provider's biometric prompt cancellation.
                     onCancelFlowAndFinish()
                 }
-                // TODO(b/326243754) : Propagate to provider
+                // TODO(b/333445772) : Propagate to provider
             }
 
             override fun onAuthenticationFailed() {
                 super.onAuthenticationFailed()
                 Log.d(TAG, "Authentication failed.")
-                // TODO(b/326243754) : Propagate to provider
             }
         }
     return callback
@@ -299,7 +358,7 @@
     if (getRequestDisplayInfo != null && getProviderInfoList != null &&
         getProviderDisplayInfo != null) {
         if (selectedEntry !is CredentialEntryInfo) { return null }
-        return getBiometricDisplayValues(getProviderInfoList,
+        return retrieveBiometricGetDisplayValues(getProviderInfoList,
             context, getRequestDisplayInfo, selectedEntry)
     }
     return null
@@ -308,7 +367,8 @@
 /**
  * Creates the [BiometricDisplayInfo] for create flows, and early handles conditional
  * checking between the two. The reason for this method matches the logic for the
- * [validateBiometricGetFlow] with the only difference being that this is for the create flow.
+ * [validateAndRetrieveBiometricGetDisplayInfo] with the only difference being that this is for
+ * the create flow.
  */
 private fun validateAndRetrieveBiometricCreateDisplayInfo(
     createRequestDisplayInfo: com.android.credentialmanager.createflow.RequestDisplayInfo?,
@@ -318,8 +378,8 @@
 ): BiometricDisplayInfo? {
     if (createRequestDisplayInfo != null && createProviderInfo != null) {
         if (selectedEntry !is CreateOptionInfo) { return null }
-        return createBiometricDisplayValues(createRequestDisplayInfo, createProviderInfo, context,
-            selectedEntry)
+        return retrieveBiometricCreateDisplayValues(createRequestDisplayInfo, createProviderInfo,
+            context, selectedEntry)
     }
     return null
 }
@@ -330,16 +390,16 @@
  * to the original selector. Note that these redundant checks are just failsafe; the original
  * flow should never reach here with invalid params.
  */
-private fun getBiometricDisplayValues(
+private fun retrieveBiometricGetDisplayValues(
     getProviderInfoList: List<ProviderInfo>,
     context: Context,
     getRequestDisplayInfo: RequestDisplayInfo,
     selectedEntry: CredentialEntryInfo,
 ): BiometricDisplayInfo? {
-    var icon: Bitmap? = null
-    var providerName: String? = null
-    var displayTitleText: String? = null
-    var descriptionText: String? = null
+    val icon: Bitmap?
+    val providerName: String?
+    val displayTitleText: String?
+    val descriptionText: String?
     val primaryAccountsProviderInfo = retrievePrimaryAccountProviderInfo(selectedEntry.providerId,
         getProviderInfoList)
     icon = primaryAccountsProviderInfo?.icon?.toBitmap()
@@ -373,7 +433,7 @@
  * if this is called, a result is guaranteed. Specifically, this is guaranteed to return a non-null
  * value unlike the get counterpart.
  */
-private fun createBiometricDisplayValues(
+private fun retrieveBiometricCreateDisplayValues(
     createRequestDisplayInfo: com.android.credentialmanager.createflow.RequestDisplayInfo,
     createProviderInfo: EnabledProviderInfo,
     context: Context,
@@ -401,7 +461,7 @@
         },
         createRequestDisplayInfo.appName,
     )
-    // TODO(b/327620327) : Add a subtitle and any other recently aligned ideas
+    // TODO(b/333445112) : Add a subtitle and any other recently aligned ideas
     return BiometricDisplayInfo(providerIcon = icon, providerName = providerName,
         displayTitleText = displayTitleText, descriptionForCredential = descriptionText,
         biometricRequestInfo = selectedEntry.biometricRequest as BiometricRequestInfo)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricPromptState.kt
similarity index 62%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
copy to packages/CredentialManager/src/com/android/credentialmanager/common/BiometricPromptState.kt
index f6140f5..e1aa041 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricPromptState.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +16,11 @@
 
 package com.android.credentialmanager.common
 
-enum class FlowType {
-    GET,
-    CREATE
+enum class BiometricPromptState {
+    /** The biometric prompt hasn't been activated. */
+    INACTIVE,
+    /** The biometric prompt is active but data hasn't been returned yet. */
+    PENDING,
+    /** The biometric prompt has closed and returned data we then send to the provider activity. */
+    COMPLETE
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 25fb477..122b896 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -46,11 +46,13 @@
 import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.credentialmanager.CredentialSelectorViewModel
 import com.android.credentialmanager.R
+import com.android.credentialmanager.common.BiometricFlowType
+import com.android.credentialmanager.common.BiometricPromptState
 import com.android.credentialmanager.model.EntryInfo
 import com.android.credentialmanager.model.CredentialType
 import com.android.credentialmanager.common.ProviderActivityState
 import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
-import com.android.credentialmanager.common.runBiometricFlow
+import com.android.credentialmanager.common.runBiometricFlowForCreate
 import com.android.credentialmanager.common.ui.ActionButton
 import com.android.credentialmanager.common.ui.BodyMediumText
 import com.android.credentialmanager.common.ui.BodySmallText
@@ -111,7 +113,11 @@
                                 onBiometricEntrySelected =
                                 viewModel::createFlowOnEntrySelected,
                                 fallbackToOriginalFlow =
-                                viewModel::getFlowOnBackToPrimarySelectionScreen,
+                                viewModel::fallbackFromBiometricToNormalFlow,
+                                getBiometricPromptState =
+                                viewModel::getBiometricPromptState,
+                                onBiometricPromptStateChange =
+                                viewModel::onBiometricPromptStateChange
                             )
                         CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
                                 requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
@@ -578,18 +584,22 @@
     onBiometricEntrySelected: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit,
     onCancelFlowAndFinish: () -> Unit,
     onIllegalScreenStateAndFinish: (String) -> Unit,
-    fallbackToOriginalFlow: () -> Unit,
+    fallbackToOriginalFlow: (BiometricFlowType) -> Unit,
+    getBiometricPromptState: () -> BiometricPromptState,
+    onBiometricPromptStateChange: (BiometricPromptState) -> Unit,
 ) {
     if (biometricEntry == null) {
-        fallbackToOriginalFlow()
+        fallbackToOriginalFlow(BiometricFlowType.CREATE)
         return
     }
-    runBiometricFlow(
+    runBiometricFlowForCreate(
         biometricEntry = biometricEntry,
         context = LocalContext.current,
         openMoreOptionsPage = onMoreOptionSelected,
         sendDataToProvider = onBiometricEntrySelected,
         onCancelFlowAndFinish = onCancelFlowAndFinish,
+        getBiometricPromptState = getBiometricPromptState,
+        onBiometricPromptStateChange = onBiometricPromptStateChange,
         createRequestDisplayInfo = requestDisplayInfo,
         createProviderInfo = enabledProviderInfo,
         onBiometricFailureFallback = fallbackToOriginalFlow,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 1d262ba..ddd4139 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -78,13 +78,8 @@
 */
 internal fun isBiometricFlow(
     activeEntry: ActiveEntry,
-    sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
-    requestDisplayInfo: RequestDisplayInfo,
-) = findBiometricFlowEntry(activeEntry, isFlowAutoSelectable(
-    requestDisplayInfo = requestDisplayInfo,
-    activeEntry = activeEntry,
-    sortedCreateOptionsPairs = sortedCreateOptionsPairs
-)) != null
+    isAutoSelectFlow: Boolean,
+) = findBiometricFlowEntry(activeEntry, isAutoSelectFlow) != null
 
 /**
  * This utility presents the correct resource string for the create flows title conditionally.
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 6d1a3dd..72b7814 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -52,9 +52,11 @@
 import androidx.core.graphics.drawable.toBitmap
 import com.android.credentialmanager.CredentialSelectorViewModel
 import com.android.credentialmanager.R
+import com.android.credentialmanager.common.BiometricFlowType
+import com.android.credentialmanager.common.BiometricPromptState
 import com.android.credentialmanager.common.ProviderActivityState
 import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
-import com.android.credentialmanager.common.runBiometricFlow
+import com.android.credentialmanager.common.runBiometricFlowForGet
 import com.android.credentialmanager.common.ui.ActionButton
 import com.android.credentialmanager.common.ui.ActionEntry
 import com.android.credentialmanager.common.ui.ConfirmButton
@@ -154,7 +156,11 @@
                                 onBiometricEntrySelected =
                                 viewModel::getFlowOnEntrySelected,
                                 fallbackToOriginalFlow =
-                                viewModel::getFlowOnBackToPrimarySelectionScreen,
+                                viewModel::fallbackFromBiometricToNormalFlow,
+                                getBiometricPromptState =
+                                viewModel::getBiometricPromptState,
+                                onBiometricPromptStateChange =
+                                viewModel::onBiometricPromptStateChange
                             )
                         } else {
                             AllSignInOptionCard(
@@ -218,19 +224,23 @@
     providerInfoList: List<ProviderInfo>,
     providerDisplayInfo: ProviderDisplayInfo,
     onBiometricEntrySelected: (EntryInfo, BiometricPrompt.AuthenticationResult?) -> Unit,
-    fallbackToOriginalFlow: () -> Unit,
+    fallbackToOriginalFlow: (BiometricFlowType) -> Unit,
+    getBiometricPromptState: () -> BiometricPromptState,
+    onBiometricPromptStateChange: (BiometricPromptState) -> Unit,
 ) {
     if (biometricEntry == null) {
-        fallbackToOriginalFlow()
+        fallbackToOriginalFlow(BiometricFlowType.GET)
         return
     }
-    runBiometricFlow(
+    runBiometricFlowForGet(
         biometricEntry = biometricEntry,
         context = LocalContext.current,
         openMoreOptionsPage = onMoreOptionSelected,
         sendDataToProvider = onBiometricEntrySelected,
         onCancelFlowAndFinish = onCancelFlowAndFinish,
         onIllegalStateAndFinish = onIllegalStateAndFinish,
+        getBiometricPromptState = getBiometricPromptState,
+        onBiometricPromptStateChange = onBiometricPromptStateChange,
         getRequestDisplayInfo = requestDisplayInfo,
         getProviderInfoList = providerInfoList,
         getProviderDisplayInfo = providerDisplayInfo,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index ac776af..b03407b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -286,7 +286,7 @@
         GetScreenState.REMOTE_ONLY
     else if (isRequestForAllOptions)
         GetScreenState.ALL_SIGN_IN_OPTIONS
-    else if (isBiometricFlow(providerDisplayInfo))
+    else if (isBiometricFlow(providerDisplayInfo, isFlowAutoSelectable(providerDisplayInfo)))
         GetScreenState.BIOMETRIC_SELECTION
     else GetScreenState.PRIMARY_SELECTION
 }
@@ -294,9 +294,14 @@
 /**
  * Determines if the flow is a biometric flow by taking into account autoselect criteria.
  */
-internal fun isBiometricFlow(providerDisplayInfo: ProviderDisplayInfo) =
-    findBiometricFlowEntry(providerDisplayInfo,
-        findAutoSelectEntry(providerDisplayInfo) != null) != null
+internal fun isBiometricFlow(providerDisplayInfo: ProviderDisplayInfo, isAutoSelectFlow: Boolean) =
+    findBiometricFlowEntry(providerDisplayInfo, isAutoSelectFlow) != null
+
+/**
+ * Determines if the flow is an autoselect flow.
+ */
+internal fun isFlowAutoSelectable(providerDisplayInfo: ProviderDisplayInfo) =
+    findAutoSelectEntry(providerDisplayInfo) != null
 
 internal class CredentialEntryInfoComparatorByTypeThenTimestamp(
         val typePriorityMap: Map<String, Int>,
diff --git a/packages/InputDevices/res/raw/keyboard_layout_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
index fbb9bb6..1fb0924 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_german.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
@@ -28,82 +28,93 @@
 
 key GRAVE {
     label:                              '^'
-    base:                               '^'
+    base:                               '\u0302'
     shift:                              '\u00b0'
 }
 
 key 1 {
     label:                              '1'
     base:                               '1'
-    shift:                              '!'
+    shift, capslock:                    '!'
+    shift+capslock:                     '1'
 }
 
 key 2 {
     label:                              '2'
     base:                               '2'
-    shift:                              '"'
+    shift, capslock:                    '"'
+    shift+capslock:                     '2'
     ralt:                               '\u00b2'
 }
 
 key 3 {
     label:                              '3'
     base:                               '3'
-    shift:                              '\u00a7'
+    shift, capslock:                    '\u00a7'
+    shift+capslock:                     '3'
     ralt:                               '\u00b3'
 }
 
 key 4 {
     label:                              '4'
     base:                               '4'
-    shift:                              '$'
+    shift, capslock:                    '$'
+    shift+capslock:                     '4'
 }
 
 key 5 {
     label:                              '5'
     base:                               '5'
-    shift:                              '%'
+    shift, capslock:                    '%'
+    shift+capslock:                     '5'
 }
 
 key 6 {
     label:                              '6'
     base:                               '6'
-    shift:                              '&'
+    shift, capslock:                    '&'
+    shift+capslock:                     '6'
 }
 
 key 7 {
     label:                              '7'
     base:                               '7'
-    shift:                              '/'
+    shift, capslock:                    '/'
+    shift+capslock:                     '7'
     ralt:                               '{'
 }
 
 key 8 {
     label:                              '8'
     base:                               '8'
-    shift:                              '('
+    shift, capslock:                    '('
+    shift+capslock:                     '8'
     ralt:                               '['
 }
 
 key 9 {
     label:                              '9'
     base:                               '9'
-    shift:                              ')'
+    shift, capslock:                    ')'
+    shift+capslock:                     '9'
     ralt:                               ']'
 }
 
 key 0 {
     label:                              '0'
     base:                               '0'
-    shift:                              '='
+    shift, capslock:                    '='
+    shift+capslock:                     '0'
     ralt:                               '}'
 }
 
 key SLASH {
     label:                              '\u00df'
     base:                               '\u00df'
-    capslock:                           '\u1e9e'
-    shift:                              '?'
+    shift, capslock:                    '?'
+    shift+capslock:                     '\u00df'
     ralt:                               '\\'
+    shift+ralt:                         '\u1e9e'
 }
 
 key EQUALS {
@@ -196,7 +207,8 @@
 key RIGHT_BRACKET {
     label:                              '+'
     base:                               '+'
-    shift:                              '*'
+    shift, capslock:                    '*'
+    shift+capslock:                     '+'
     ralt:                               '~'
 }
 
@@ -282,7 +294,8 @@
 key BACKSLASH {
     label:                              '#'
     base:                               '#'
-    shift:                              '\''
+    shift, capslock:                    '\''
+    shift+capslock:                     '#'
 }
 
 ### ROW 4
@@ -347,13 +360,15 @@
 key COMMA {
     label:                              ','
     base:                               ','
-    shift:                              ';'
+    shift, capslock:                    ';'
+    shift+capslock:                     ','
 }
 
 key PERIOD {
     label:                              '.'
     base:                               '.'
-    shift:                              ':'
+    shift, capslock:                    ':'
+    shift+capslock:                     '.'
 }
 
 key MINUS {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
index 8f5d07c..407ab5f 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
@@ -245,8 +245,7 @@
     }
 
     private static boolean isArchivingEnabled() {
-        return android.content.pm.Flags.archiving()
-                || SystemProperties.getBoolean("pm.archiving.enabled", false);
+        return android.content.pm.Flags.archiving();
     }
 
     private boolean isCloneProfile(UserHandle userHandle) {
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_mainSwitchPreference.png
index 3e016f7..75c8e6e 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_mainSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_spinner.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_spinner.png
index d156f95..06f0059 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_spinner.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_mainSwitchPreference.png
index b8bb25f..b72c8db 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_mainSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_spinner.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_spinner.png
index d156f95..06f0059 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_spinner.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_twoTargetSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_twoTargetSwitchPreference.png
index 9044208..e43f27d 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_twoTargetSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_twoTargetSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_mainSwitchPreference.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_mainSwitchPreference.png
index 36cbadc..15c86dc 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_mainSwitchPreference.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_mainSwitchPreference.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_spinner.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_spinner.png
index a279481..5be3a21 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_spinner.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_spinner.png
Binary files differ
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index a395266..e1e1ee5 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -151,7 +151,7 @@
     }
 
     private fun isArchivingEnabled(featureFlags: FeatureFlags) =
-            featureFlags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+            featureFlags.archiving()
 
     override fun showSystemPredicate(
         userIdFlow: Flow<Int>,
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index e09ab00..9ec5caa 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -36,14 +36,14 @@
   name: "enable_le_audio_sharing"
   namespace: "pixel_cross_device_control"
   description: "Gates whether to enable LE audio sharing"
-  bug: "305620450"
+  bug: "323125723"
 }
 
 flag {
   name: "enable_le_audio_qr_code_private_broadcast_sharing"
   namespace: "pixel_cross_device_control"
   description: "Gates whether to enable LE audio private broadcast sharing via QR code"
-  bug: "308368124"
+  bug: "323125723"
 }
 
 flag {
diff --git a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
index 89d6ac3..3ed1724 100644
--- a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
+++ b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
@@ -53,7 +53,7 @@
     <EditText
         android:id="@+id/user_name"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/user_name_height_in_user_info_dialog"
+        android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:minWidth="200dp"
         android:layout_marginStart="6dp"
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 2bd4d02..ab04904 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -82,7 +82,6 @@
     <dimen name="add_a_photo_circled_padding">6dp</dimen>
     <dimen name="user_photo_size_in_user_info_dialog">112dp</dimen>
     <dimen name="add_a_photo_icon_size_in_user_info_dialog">32dp</dimen>
-    <dimen name="user_name_height_in_user_info_dialog">48sp</dimen>
 
     <!-- Minimum increment between density scales. -->
     <fraction name="display_density_min_scale_interval">9%</fraction>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 64cf5c64..6c12cb7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -78,6 +78,7 @@
     public static final String ACTION_LE_AUDIO_SHARING_STATE_CHANGE =
             "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE";
     public static final String EXTRA_LE_AUDIO_SHARING_STATE = "BLUETOOTH_LE_AUDIO_SHARING_STATE";
+    public static final String EXTRA_BLUETOOTH_DEVICE = "BLUETOOTH_DEVICE";
     public static final int BROADCAST_STATE_UNKNOWN = 0;
     public static final int BROADCAST_STATE_ON = 1;
     public static final int BROADCAST_STATE_OFF = 2;
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index f42efe2..c891dfc 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -840,6 +840,8 @@
                         Settings.Secure.BIOMETRIC_APP_ENABLED,
                         Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED,
                         Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED,
+                        Settings.Secure.BIOMETRIC_FINGERPRINT_VIRTUAL_ENABLED,
+                        Settings.Secure.BIOMETRIC_FACE_VIRTUAL_ENABLED,
                         Settings.Secure.BLUETOOTH_ADDR_VALID,
                         Settings.Secure.BLUETOOTH_ADDRESS,
                         Settings.Secure.BLUETOOTH_NAME,
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml b/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml
index 648cc3b..a98625f 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml
@@ -40,7 +40,7 @@
             android:exported="true"
             android:label="@string/accessibility_menu_settings_name"
             android:launchMode="singleTop"
-            android:theme="@style/Theme.SettingsBase">
+            android:theme="@style/SettingsTheme">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
 
@@ -59,4 +59,4 @@
             <action android:name="android.intent.action.VOICE_COMMAND" />
         </intent>
     </queries>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
index 4169155..a138fa9 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values/styles.xml
@@ -21,6 +21,11 @@
     <item name="android:colorControlNormal">@color/colorControlNormal</item>
   </style>
 
+  <style name="SettingsTheme" parent="Theme.SettingsBase">
+    <!-- Quick fix so that the preference page doesn't render under its parent header. -->
+    <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
+  </style>
+
   <!--The basic theme for service and test case only-->
   <style name="A11yMenuBaseTheme" parent="android:Theme.DeviceDefault.Light">
     <item name="android:windowActionBar">false</item>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
index 5f3d1ea..0ab99fa 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
@@ -30,8 +30,6 @@
 import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_TOGGLE_MENU;
 import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.PACKAGE_NAME;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Instrumentation;
 import android.app.KeyguardManager;
@@ -449,7 +447,10 @@
         closeScreen();
         wakeUpScreen();
 
-        assertThat(isMenuVisible()).isFalse();
+        TestUtils.waitUntil("Menu did not close.",
+                TIMEOUT_UI_CHANGE_S,
+                () -> !isMenuVisible()
+        );
     }
 
     @Test
diff --git a/packages/SystemUI/aconfig/Android.bp b/packages/SystemUI/aconfig/Android.bp
index 2a32b58..1858c80 100644
--- a/packages/SystemUI/aconfig/Android.bp
+++ b/packages/SystemUI/aconfig/Android.bp
@@ -45,4 +45,5 @@
 java_aconfig_library {
     name: "com_android_systemui_flags_lib",
     aconfig_declarations: "com_android_systemui_flags",
+    sdk_version: "system_current",
 }
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 6810aac9..fd2fa07 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -148,6 +148,16 @@
 }
 
 flag {
+   name: "pss_app_selector_recents_split_screen"
+   namespace: "systemui"
+   description: "Allows recent apps selected for partial screenshare to be launched in split screen mode"
+   bug: "320449039"
+   metadata {
+        purpose: PURPOSE_BUGFIX
+   }
+}
+
+flag {
     name: "notifications_background_icons"
     namespace: "systemui"
     description: "Moves part of the notification icon updates to the background."
@@ -328,6 +338,16 @@
 }
 
 flag {
+    name: "status_bar_monochrome_icons_fix"
+    namespace: "systemui"
+    description: "Fixes the status bar icon size when drawing InsetDrawables (ie. monochrome icons)"
+    bug: "329091967"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "compose_bouncer"
     namespace: "systemui"
     description: "Use the new compose bouncer in SystemUI"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/PaintDrawCallback.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/PaintDrawCallback.kt
new file mode 100644
index 0000000..d50979c
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/PaintDrawCallback.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.systemui.surfaceeffects
+
+import android.graphics.Paint
+import android.graphics.RenderEffect
+
+/**
+ * A callback with a [Paint] object that contains shader info, which is triggered every frame while
+ * animation is playing. Note that the [Paint] object here is always the same instance.
+ *
+ * This approach is more performant than other ones because [RenderEffect] forces an intermediate
+ * render pass of the View to a texture to feed into it.
+ *
+ * The usage of this callback is as follows:
+ * <pre>{@code
+ *     private var paint: Paint? = null
+ *     // Override [View.onDraw].
+ *     override fun onDraw(canvas: Canvas) {
+ *         // RuntimeShader requires hardwareAcceleration.
+ *         if (!canvas.isHardwareAccelerated) return
+ *
+ *         paint?.let { canvas.drawPaint(it) }
+ *     }
+ *
+ *     // Given that this is called [PaintDrawCallback.onDraw]
+ *     fun draw(paint: Paint) {
+ *         this.paint = paint
+ *
+ *         // Must call invalidate to trigger View#onDraw
+ *         invalidate()
+ *     }
+ * }</pre>
+ *
+ * Please refer to [RenderEffectDrawCallback] for alternative approach.
+ */
+interface PaintDrawCallback {
+    fun onDraw(paint: Paint)
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/RenderEffectDrawCallback.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/RenderEffectDrawCallback.kt
new file mode 100644
index 0000000..db7ee58
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/RenderEffectDrawCallback.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.systemui.surfaceeffects
+
+import android.graphics.RenderEffect
+
+/**
+ * A callback with a [RenderEffect] object that contains shader info, which is triggered every frame
+ * while animation is playing. Note that the [RenderEffect] instance is different each time to
+ * update shader uniforms.
+ *
+ * The usage of this callback is as follows:
+ * <pre>{@code
+ *     private val xEffectDrawingCallback = RenderEffectDrawCallback() {
+ *         val myOtherRenderEffect = createOtherRenderEffect()
+ *         val chainEffect = RenderEffect.createChainEffect(renderEffect, myOtherRenderEffect)
+ *         myView.setRenderEffect(chainEffect)
+ *     }
+ *
+ *     private val xEffect = XEffect(config, xEffectDrawingCallback)
+ * }</pre>
+ */
+interface RenderEffectDrawCallback {
+    fun onDraw(renderEffect: RenderEffect)
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt
index 1c763e8..211b84f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt
@@ -22,6 +22,8 @@
 import android.graphics.Paint
 import android.graphics.RenderEffect
 import android.view.View
+import com.android.systemui.surfaceeffects.PaintDrawCallback
+import com.android.systemui.surfaceeffects.RenderEffectDrawCallback
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader
 
@@ -334,52 +336,31 @@
         )
     }
 
-    companion object {
+    /**
+     * States of the loading effect animation.
+     *
+     * <p>The state is designed to be follow the order below: [AnimationState.EASE_IN],
+     * [AnimationState.MAIN], [AnimationState.EASE_OUT]. Note that ease in and out don't necessarily
+     * mean the acceleration and deceleration in the animation curve. They simply mean each stage of
+     * the animation. (i.e. Intro, core, and rest)
+     */
+    enum class AnimationState {
+        EASE_IN,
+        MAIN,
+        EASE_OUT,
+        NOT_PLAYING
+    }
+
+    /** Optional callback that is triggered when the animation state changes. */
+    interface AnimationStateChangedCallback {
         /**
-         * States of the loading effect animation.
-         *
-         * <p>The state is designed to be follow the order below: [AnimationState.EASE_IN],
-         * [AnimationState.MAIN], [AnimationState.EASE_OUT]. Note that ease in and out don't
-         * necessarily mean the acceleration and deceleration in the animation curve. They simply
-         * mean each stage of the animation. (i.e. Intro, core, and rest)
+         * A callback that's triggered when the [AnimationState] changes. Example usage is
+         * performing a cleanup when [AnimationState] becomes [NOT_PLAYING].
          */
-        enum class AnimationState {
-            EASE_IN,
-            MAIN,
-            EASE_OUT,
-            NOT_PLAYING
-        }
+        fun onStateChanged(oldState: AnimationState, newState: AnimationState) {}
+    }
 
-        /** Client must implement one of the draw callbacks. */
-        interface PaintDrawCallback {
-            /**
-             * A callback with a [Paint] object that contains shader info, which is triggered every
-             * frame while animation is playing. Note that the [Paint] object here is always the
-             * same instance.
-             */
-            fun onDraw(loadingPaint: Paint)
-        }
-
-        interface RenderEffectDrawCallback {
-            /**
-             * A callback with a [RenderEffect] object that contains shader info, which is triggered
-             * every frame while animation is playing. Note that the [RenderEffect] instance is
-             * different each time to update shader uniforms.
-             */
-            fun onDraw(loadingRenderEffect: RenderEffect)
-        }
-
-        /** Optional callback that is triggered when the animation state changes. */
-        interface AnimationStateChangedCallback {
-            /**
-             * A callback that's triggered when the [AnimationState] changes. Example usage is
-             * performing a cleanup when [AnimationState] becomes [NOT_PLAYING].
-             */
-            fun onStateChanged(oldState: AnimationState, newState: AnimationState) {}
-        }
-
+    private companion object {
         private const val MS_TO_SEC = 0.001f
-
-        private val TAG = LoadingEffect::class.java.simpleName
     }
 }
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 bdd888f..4533f58 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
@@ -26,6 +26,7 @@
 import com.android.compose.animation.scene.transitions
 import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.CommunalTransitionKeys
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
 import com.android.systemui.res.R
@@ -41,6 +42,11 @@
 }
 
 val sceneTransitions = transitions {
+    to(CommunalScenes.Communal, key = CommunalTransitionKeys.SimpleFade) {
+        spec = tween(durationMillis = 250)
+        fade(Communal.Elements.Scrim)
+        fade(Communal.Elements.Content)
+    }
     to(CommunalScenes.Communal) {
         spec = tween(durationMillis = 1000)
         translate(Communal.Elements.Content, Edge.Right)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt
index ccb5d36..fa052e8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt
@@ -17,15 +17,12 @@
 package com.android.systemui.volume.panel.component.anc
 
 import com.android.systemui.volume.panel.component.anc.domain.AncAvailabilityCriteria
-import com.android.systemui.volume.panel.component.anc.ui.composable.AncPopup
-import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel
-import com.android.systemui.volume.panel.component.button.ui.composable.ButtonComponent
+import com.android.systemui.volume.panel.component.anc.ui.composable.AncButtonComponent
 import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
 import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
 import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent
 import dagger.Binds
 import dagger.Module
-import dagger.Provides
 import dagger.multibindings.IntoMap
 import dagger.multibindings.StringKey
 
@@ -40,14 +37,8 @@
         criteria: AncAvailabilityCriteria
     ): ComponentAvailabilityCriteria
 
-    companion object {
-
-        @Provides
-        @IntoMap
-        @StringKey(VolumePanelComponents.ANC)
-        fun provideVolumePanelUiComponent(
-            viewModel: AncViewModel,
-            popup: AncPopup,
-        ): VolumePanelUiComponent = ButtonComponent(viewModel.button, popup::show)
-    }
+    @Binds
+    @IntoMap
+    @StringKey(VolumePanelComponents.ANC)
+    fun bindVolumePanelUiComponent(component: AncButtonComponent): VolumePanelUiComponent
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
new file mode 100644
index 0000000..00225fc
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.systemui.volume.panel.component.anc.ui.composable
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+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.draw.clip
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import com.android.systemui.res.R
+import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel
+import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
+import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope
+import javax.inject.Inject
+
+class AncButtonComponent
+@Inject
+constructor(
+    private val viewModel: AncViewModel,
+    private val ancPopup: AncPopup,
+) : ComposeVolumePanelUiComponent {
+
+    @Composable
+    override fun VolumePanelComposeScope.Content(modifier: Modifier) {
+        val slice by viewModel.buttonSlice.collectAsState()
+        val label = stringResource(R.string.volume_panel_noise_control_title)
+        Column(
+            modifier = modifier,
+            verticalArrangement = Arrangement.spacedBy(12.dp),
+            horizontalAlignment = Alignment.CenterHorizontally,
+        ) {
+            SliceAndroidView(
+                modifier =
+                    Modifier.height(64.dp)
+                        .fillMaxWidth()
+                        .semantics {
+                            role = Role.Button
+                            contentDescription = label
+                        }
+                        .clip(RoundedCornerShape(28.dp)),
+                slice = slice,
+                onWidthChanged = viewModel::onButtonSliceWidthChanged,
+                onClick = { ancPopup.show(null) }
+            )
+            Text(
+                modifier = Modifier.clearAndSetSemantics {},
+                text = label,
+                style = MaterialTheme.typography.labelMedium,
+                maxLines = 1,
+                overflow = TextOverflow.Ellipsis,
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
index 9f0da00..2af042a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
@@ -16,9 +16,6 @@
 
 package com.android.systemui.volume.panel.component.anc.ui.composable
 
-import android.content.Context
-import android.view.ContextThemeWrapper
-import android.view.View
 import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.material3.MaterialTheme
@@ -30,9 +27,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.viewinterop.AndroidView
 import androidx.slice.Slice
-import androidx.slice.widget.SliceView
 import com.android.systemui.animation.Expandable
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -49,7 +44,7 @@
 ) {
 
     /** Shows a popup with the [expandable] animation. */
-    fun show(expandable: Expandable) {
+    fun show(expandable: Expandable?) {
         volumePanelPopup.show(expandable, { Title() }, { Content(it) })
     }
 
@@ -66,49 +61,18 @@
 
     @Composable
     private fun Content(dialog: SystemUIDialog) {
-        val slice: Slice? by viewModel.slice.collectAsState()
+        val isAvailable by viewModel.isAvailable.collectAsState(true)
 
-        if (slice == null) {
+        if (!isAvailable) {
             SideEffect { dialog.dismiss() }
             return
         }
 
-        AndroidView<SliceView>(
+        val slice by viewModel.popupSlice.collectAsState()
+        SliceAndroidView(
             modifier = Modifier.fillMaxWidth(),
-            factory = { context: Context ->
-                SliceView(ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel))
-                    .apply {
-                        mode = SliceView.MODE_LARGE
-                        isScrollable = false
-                        importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
-                        setShowTitleItems(true)
-                        addOnLayoutChangeListener(
-                            OnWidthChangedLayoutListener(viewModel::changeSliceWidth)
-                        )
-                    }
-            },
-            update = { sliceView: SliceView -> sliceView.slice = slice }
+            slice = slice,
+            onWidthChanged = viewModel::onPopupSliceWidthChanged
         )
     }
-
-    private class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) :
-        View.OnLayoutChangeListener {
-        override fun onLayoutChange(
-            v: View?,
-            left: Int,
-            top: Int,
-            right: Int,
-            bottom: Int,
-            oldLeft: Int,
-            oldTop: Int,
-            oldRight: Int,
-            oldBottom: Int
-        ) {
-            val newWidth = right - left
-            val oldWidth = oldRight - oldLeft
-            if (oldWidth != newWidth) {
-                widthChanged(newWidth)
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
new file mode 100644
index 0000000..f354b80
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.systemui.volume.panel.component.anc.ui.composable
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.ContextThemeWrapper
+import android.view.MotionEvent
+import android.view.View
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.slice.Slice
+import androidx.slice.widget.SliceView
+import com.android.systemui.res.R
+
+@Composable
+fun SliceAndroidView(
+    slice: Slice?,
+    modifier: Modifier = Modifier,
+    onWidthChanged: ((Int) -> Unit)? = null,
+    onClick: (() -> Unit)? = null,
+) {
+    AndroidView(
+        modifier = modifier,
+        factory = { context: Context ->
+            ClickableSliceView(
+                    ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel),
+                    onClick,
+                )
+                .apply {
+                    mode = SliceView.MODE_LARGE
+                    isScrollable = false
+                    importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
+                    setShowTitleItems(true)
+                    if (onWidthChanged != null) {
+                        addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged))
+                    }
+                    if (onClick != null) {
+                        setOnClickListener { onClick() }
+                    }
+                }
+        },
+        update = { sliceView: SliceView -> sliceView.slice = slice }
+    )
+}
+
+class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) :
+    View.OnLayoutChangeListener {
+
+    override fun onLayoutChange(
+        v: View?,
+        left: Int,
+        top: Int,
+        right: Int,
+        bottom: Int,
+        oldLeft: Int,
+        oldTop: Int,
+        oldRight: Int,
+        oldBottom: Int
+    ) {
+        val newWidth = right - left
+        val oldWidth = oldRight - oldLeft
+        if (oldWidth != newWidth) {
+            widthChanged(newWidth)
+        }
+    }
+}
+
+/**
+ * [SliceView] that prioritises [onClick] when its clicked instead of passing the event to the slice
+ * first.
+ */
+@SuppressLint("ViewConstructor") // only used in this class
+private class ClickableSliceView(
+    context: Context,
+    private val onClick: (() -> Unit)?,
+) : SliceView(context) {
+
+    init {
+        if (onClick != null) {
+            setOnClickListener {}
+        }
+    }
+
+    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
+        return onClick != null || super.onInterceptTouchEvent(ev)
+    }
+
+    override fun onClick(v: View?) {
+        onClick?.let { it() } ?: super.onClick(v)
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt
index 9f9bc62..b489dfc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt
@@ -59,7 +59,7 @@
      * @param content is the popup body
      */
     fun show(
-        expandable: Expandable,
+        expandable: Expandable?,
         title: @Composable (SystemUIDialog) -> Unit,
         content: @Composable (SystemUIDialog) -> Unit,
     ) {
@@ -70,7 +70,7 @@
             ) {
                 PopupComposable(it, title, content)
             }
-        val controller = expandable.dialogTransitionController()
+        val controller = expandable?.dialogTransitionController()
         if (controller == null) {
             dialog.show()
         } else {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 1120914..2d4b63e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -66,6 +66,7 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import com.android.systemui.scene.shared.model.FakeSceneDataSource
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
@@ -209,7 +210,6 @@
 
         val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository())
         featureFlags = FakeFeatureFlags()
-        featureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
         featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
 
         mSetFlagsRule.enableFlags(
@@ -217,7 +217,8 @@
         )
         mSetFlagsRule.disableFlags(
             FLAG_SIDEFPS_CONTROLLER_REFACTOR,
-            AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR
+            AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
+            AConfigFlags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,
         )
 
         keyguardPasswordViewController =
@@ -267,7 +268,7 @@
                 falsingManager,
                 userSwitcherController,
                 featureFlags,
-                kosmos.fakeSceneContainerFlags,
+                kosmos.sceneContainerFlags,
                 globalSettings,
                 sessionTracker,
                 Optional.of(sideFpsController),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index a944afb..76f15d2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -120,19 +120,20 @@
         }
 
     @Test
-    fun exitingDream_forceCommunalScene() =
+    fun occluded_forceBlankScene() =
         with(kosmos) {
             testScope.runTest {
                 val scene by collectLastValue(communalInteractor.desiredScene)
-                assertThat(scene).isEqualTo(CommunalScenes.Blank)
+                communalInteractor.changeScene(CommunalScenes.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
 
                 updateDocked(true)
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
-                    from = KeyguardState.DREAMING,
-                    to = KeyguardState.LOCKSCREEN,
+                    from = KeyguardState.GLANCEABLE_HUB,
+                    to = KeyguardState.OCCLUDED,
                     testScope = this
                 )
-                assertThat(scene).isEqualTo(CommunalScenes.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
             }
         }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 9a13bb2..8bc6a00 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -32,7 +32,6 @@
 import android.hardware.face.FaceSensorProperties
 import android.hardware.face.FaceSensorPropertiesInternal
 import android.os.CancellationSignal
-import android.view.Display
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.InstanceId.fakeInstanceId
@@ -54,7 +53,6 @@
 import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus
 import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
 import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus
-import com.android.systemui.display.data.repository.display
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FakeFeatureFlags
@@ -697,9 +695,7 @@
             )
             runCurrent()
 
-            displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_OFF)))
-            displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY)
-
+            displayRepository.setDefaultDisplayOff(true)
             runCurrent()
 
             assertThat(canFaceAuthRun()).isTrue()
@@ -717,10 +713,7 @@
                 )
                 runCurrent()
 
-                displayRepository.emit(
-                    setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_OFF))
-                )
-                displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY)
+                displayRepository.setDefaultDisplayOff(true)
             }
         }
 
@@ -827,7 +820,7 @@
         }
 
     @Test
-    fun isAuthenticatedIsResetToFalseWhenTransitioningToGone() =
+    fun isAuthenticatedIsResetToFalseWhenKeyguardDoneAnimationsFinished() =
         testScope.runTest {
             initCollectors()
             allPreconditionsToRunFaceAuthAreTrue()
@@ -840,13 +833,7 @@
 
             assertThat(authenticated()).isTrue()
 
-            keyguardTransitionRepository.sendTransitionStep(
-                TransitionStep(
-                    transitionState = TransitionState.STARTED,
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.GONE,
-                )
-            )
+            keyguardRepository.keyguardDoneAnimationsFinished()
 
             assertThat(authenticated()).isFalse()
         }
@@ -1167,8 +1154,7 @@
         faceLockoutResetCallback.value.onLockoutReset(0)
         bouncerRepository.setAlternateVisible(true)
         keyguardRepository.setKeyguardShowing(true)
-        displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_ON)))
-        displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY)
+        displayRepository.setDefaultDisplayOff(false)
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.AOD,
             to = KeyguardState.LOCKSCREEN,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 6d7a0a9..1dd5d07 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
@@ -75,7 +76,7 @@
             repository = repository,
             commandQueue = commandQueue,
             powerInteractor = PowerInteractorFactory.create().powerInteractor,
-            sceneContainerFlags = kosmos.fakeSceneContainerFlags,
+            sceneContainerFlags = kosmos.sceneContainerFlags,
             bouncerRepository = bouncerRepository,
             configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()),
             shadeRepository = shadeRepository,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
index 78bdfb3..5bf0f4b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt
@@ -36,6 +36,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -45,16 +46,19 @@
 class AlternateBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
     val kosmos =
         testKosmos().apply {
-            fakeFeatureFlagsClassic.apply {
-                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
-                set(Flags.FULL_SCREEN_USER_SWITCHER, false)
-            }
+            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
         }
+
     private val testScope = kosmos.testScope
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController
     private val underTest by lazy { kosmos.alternateBouncerToGoneTransitionViewModel }
 
+    @Before
+    fun setup() {
+        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
+    }
+
     @Test
     fun deviceEntryParentViewDisappear() =
         testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt
index ff41ea2..854a478 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt
@@ -32,6 +32,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -41,15 +42,17 @@
 class AlternateBouncerToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
     private val kosmos =
         testKosmos().apply {
-            fakeFeatureFlagsClassic.apply {
-                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
-                set(Flags.FULL_SCREEN_USER_SWITCHER, false)
-            }
+            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
         }
     private val testScope = kosmos.testScope
     private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
     private val underTest by lazy { kosmos.alternateBouncerToPrimaryBouncerTransitionViewModel }
 
+    @Before
+    fun setup() {
+        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
+    }
+
     @Test
     fun deviceEntryParentViewDisappear() =
         testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
index e6b3017..ee217a6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
@@ -57,10 +57,7 @@
 
     private val kosmos =
         testKosmos().apply {
-            fakeFeatureFlagsClassic.apply {
-                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
-                set(Flags.FULL_SCREEN_USER_SWITCHER, false)
-            }
+            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
         }
     private val testScope = kosmos.testScope
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
@@ -72,6 +69,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
         whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
         sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index fc604aa..973e496 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -30,11 +30,8 @@
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
-import com.android.systemui.flags.Flags
-import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -60,13 +57,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class KeyguardRootViewModelTest : SysuiTestCase() {
-    private val kosmos =
-        testKosmos().apply {
-            fakeFeatureFlagsClassic.apply { set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) }
-        }
+    private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
-    private val keyguardInteractor = kosmos.keyguardInteractor
     private val keyguardRepository = kosmos.fakeKeyguardRepository
     private val communalRepository = kosmos.communalRepository
     private val screenOffAnimationController = kosmos.screenOffAnimationController
@@ -82,7 +75,10 @@
     fun setUp() {
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
         mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION)
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+        mSetFlagsRule.disableFlags(
+            AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
+            AConfigFlags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,
+        )
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index db1d5d9..18e9009 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -44,10 +44,7 @@
 class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
     val kosmos =
         testKosmos().apply {
-            fakeFeatureFlagsClassic.apply {
-                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
-                set(Flags.FULL_SCREEN_USER_SWITCHER, false)
-            }
+            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
         }
     val testScope = kosmos.testScope
 
@@ -58,6 +55,7 @@
 
     @Before
     fun setUp() {
+        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)
         whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
         sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 426f94d..139289a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
 import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel
 import com.android.systemui.shade.domain.interactor.privacyChipInteractor
@@ -88,6 +89,7 @@
             flags,
             scope = testScope.backgroundScope,
         )
+    private val sceneInteractor = kosmos.sceneInteractor
 
     private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
 
@@ -115,11 +117,12 @@
                 notifications = kosmos.notificationsPlaceholderViewModel,
                 footerActionsViewModelFactory = footerActionsViewModelFactory,
                 footerActionsController = footerActionsController,
+                sceneInteractor = sceneInteractor,
             )
     }
 
     @Test
-    fun destinationsNotCustomizing() =
+    fun destinations_whenNotCustomizing() =
         testScope.runTest {
             overrideResource(R.bool.config_use_split_notification_shade, false)
             val destinations by collectLastValue(underTest.destinationScenes)
@@ -135,7 +138,30 @@
         }
 
     @Test
-    fun destinationsCustomizing_noDestinations() =
+    fun destinations_whenNotCustomizing_withPreviousSceneLockscreen() =
+        testScope.runTest {
+            overrideResource(R.bool.config_use_split_notification_shade, false)
+            qsFlexiglassAdapter.setCustomizing(false)
+            val destinations by collectLastValue(underTest.destinationScenes)
+
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val previousScene by collectLastValue(sceneInteractor.previousScene)
+            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+            sceneInteractor.changeScene(Scenes.QuickSettings, "reason")
+            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
+            assertThat(previousScene).isEqualTo(Scenes.Lockscreen)
+
+            assertThat(destinations)
+                .isEqualTo(
+                    mapOf(
+                        Back to UserActionResult(Scenes.Lockscreen),
+                        Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Lockscreen),
+                    )
+                )
+        }
+
+    @Test
+    fun destinations_whenCustomizing_noDestinations() =
         testScope.runTest {
             overrideResource(R.bool.config_use_split_notification_shade, false)
             val destinations by collectLastValue(underTest.destinationScenes)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt
new file mode 100644
index 0000000..db31ad5
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.systemui.scene.shared.flag
+
+import android.platform.test.flag.junit.FlagsParameterization
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_COMPOSE_LOCKSCREEN
+import com.android.systemui.Flags.FLAG_EXAMPLE_FLAG
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.andSceneContainer
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+internal class SceneContainerFlagParameterizationTest : SysuiTestCase() {
+
+    @Test
+    fun emptyAndSceneContainer() {
+        val result = FlagsParameterization.allCombinationsOf().andSceneContainer()
+        Truth.assertThat(result).hasSize(2)
+        Truth.assertThat(result[0].mOverrides[FLAG_SCENE_CONTAINER]).isFalse()
+        Truth.assertThat(result[1].mOverrides[FLAG_SCENE_CONTAINER]).isTrue()
+    }
+
+    @Test
+    fun oneUnrelatedAndSceneContainer() {
+        val unrelatedFlag = FLAG_EXAMPLE_FLAG
+        val result = FlagsParameterization.allCombinationsOf(unrelatedFlag).andSceneContainer()
+        Truth.assertThat(result).hasSize(4)
+        Truth.assertThat(result[0].mOverrides[unrelatedFlag]).isFalse()
+        Truth.assertThat(result[0].mOverrides[FLAG_SCENE_CONTAINER]).isFalse()
+        Truth.assertThat(result[1].mOverrides[unrelatedFlag]).isFalse()
+        Truth.assertThat(result[1].mOverrides[FLAG_SCENE_CONTAINER]).isTrue()
+        Truth.assertThat(result[2].mOverrides[unrelatedFlag]).isTrue()
+        Truth.assertThat(result[2].mOverrides[FLAG_SCENE_CONTAINER]).isFalse()
+        Truth.assertThat(result[3].mOverrides[unrelatedFlag]).isTrue()
+        Truth.assertThat(result[3].mOverrides[FLAG_SCENE_CONTAINER]).isTrue()
+    }
+
+    @Test
+    fun oneDependencyAndSceneContainer() {
+        val dependentFlag = FLAG_COMPOSE_LOCKSCREEN
+        val result = FlagsParameterization.allCombinationsOf(dependentFlag).andSceneContainer()
+        Truth.assertThat(result).hasSize(3)
+        Truth.assertThat(result[0].mOverrides[dependentFlag]).isFalse()
+        Truth.assertThat(result[0].mOverrides[FLAG_SCENE_CONTAINER]).isFalse()
+        Truth.assertThat(result[1].mOverrides[dependentFlag]).isTrue()
+        Truth.assertThat(result[1].mOverrides[FLAG_SCENE_CONTAINER]).isFalse()
+        Truth.assertThat(result[2].mOverrides[dependentFlag]).isTrue()
+        Truth.assertThat(result[2].mOverrides[FLAG_SCENE_CONTAINER]).isTrue()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index ac8387f..aef1d71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -20,9 +20,11 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
 import android.platform.test.annotations.DisableFlags
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX
+import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
 import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.NotificationContainerBounds
@@ -31,6 +33,7 @@
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.flags.EnableSceneContainer
 import com.android.systemui.flags.Flags
+import com.android.systemui.flags.andSceneContainer
 import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -64,19 +67,36 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 
 @SmallTest
-@RunWith(AndroidJUnit4::class)
-class SharedNotificationContainerViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+// SharedNotificationContainerViewModel is only bound when FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT is on
+@EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+class SharedNotificationContainerViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() {
+
+    companion object {
+        @JvmStatic
+        @Parameters(name = "{0}")
+        fun getParams(): List<FlagsParameterization> {
+            return FlagsParameterization.allCombinationsOf(
+                    FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX,
+                )
+                .andSceneContainer()
+        }
+    }
+
+    init {
+        mSetFlagsRule.setFlagsParameterization(flags!!)
+    }
+
     val aodBurnInViewModel = mock(AodBurnInViewModel::class.java)
     lateinit var movementFlow: MutableStateFlow<BurnInModel>
 
     val kosmos =
         testKosmos().apply {
-            fakeFeatureFlagsClassic.apply {
-                set(Flags.FULL_SCREEN_USER_SWITCHER, false)
-                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
-            }
+            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
         }
 
     init {
@@ -84,14 +104,22 @@
     }
 
     val testScope = kosmos.testScope
-    val configurationRepository = kosmos.fakeConfigurationRepository
-    val keyguardRepository = kosmos.fakeKeyguardRepository
-    val keyguardInteractor = kosmos.keyguardInteractor
-    val keyguardRootViewModel = kosmos.keyguardRootViewModel
-    val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
-    val shadeRepository = kosmos.shadeRepository
-    val sharedNotificationContainerInteractor = kosmos.sharedNotificationContainerInteractor
-    val largeScreenHeaderHelper = kosmos.mockLargeScreenHeaderHelper
+    val configurationRepository
+        get() = kosmos.fakeConfigurationRepository
+    val keyguardRepository
+        get() = kosmos.fakeKeyguardRepository
+    val keyguardInteractor
+        get() = kosmos.keyguardInteractor
+    val keyguardRootViewModel
+        get() = kosmos.keyguardRootViewModel
+    val keyguardTransitionRepository
+        get() = kosmos.fakeKeyguardTransitionRepository
+    val shadeRepository
+        get() = kosmos.shadeRepository
+    val sharedNotificationContainerInteractor
+        get() = kosmos.sharedNotificationContainerInteractor
+    val largeScreenHeaderHelper
+        get() = kosmos.mockLargeScreenHeaderHelper
 
     lateinit var underTest: SharedNotificationContainerViewModel
 
@@ -130,9 +158,9 @@
         }
 
     @Test
+    @DisableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
     fun validatePaddingTopInSplitShade_refactorFlagOff_usesLargeHeaderResource() =
         testScope.runTest {
-            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
             overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.bool.config_use_large_screen_shade_header, true)
@@ -148,9 +176,9 @@
         }
 
     @Test
+    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
     fun validatePaddingTopInSplitShade_refactorFlagOn_usesLargeHeaderHelper() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
             overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.bool.config_use_large_screen_shade_header, true)
@@ -243,9 +271,9 @@
 
     @Test
     @DisableFlags(FLAG_SCENE_CONTAINER)
+    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
     fun validateMarginTopWithLargeScreenHeader_refactorFlagOn_usesHelper() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val headerResourceHeight = 50
             val headerHelperHeight = 100
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight())
@@ -263,9 +291,9 @@
 
     @Test
     @EnableSceneContainer
+    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
     fun validateMarginTopWithLargeScreenHeader_sceneContainerFlagOn_stillZero() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val headerResourceHeight = 50
             val headerHelperHeight = 100
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight())
@@ -503,6 +531,7 @@
         }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun boundsOnLockscreenNotInSplitShade() =
         testScope.runTest {
             val bounds by collectLastValue(underTest.bounds)
@@ -523,9 +552,9 @@
         }
 
     @Test
+    @DisableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX, FLAG_SCENE_CONTAINER)
     fun boundsOnLockscreenInSplitShade_refactorFlagOff_usesLargeHeaderResource() =
         testScope.runTest {
-            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val bounds by collectLastValue(underTest.bounds)
 
             // When in split shade
@@ -547,13 +576,20 @@
             runCurrent()
 
             // Top should be equal to bounds (1) - padding adjustment (10)
-            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = -9f, bottom = 2f))
+            assertThat(bounds)
+                .isEqualTo(
+                    NotificationContainerBounds(
+                        top = -9f,
+                        bottom = 2f,
+                    )
+                )
         }
 
     @Test
+    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun boundsOnLockscreenInSplitShade_refactorFlagOn_usesLargeHeaderHelper() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val bounds by collectLastValue(underTest.bounds)
 
             // When in split shade
@@ -579,6 +615,7 @@
         }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun boundsOnShade() =
         testScope.runTest {
             val bounds by collectLastValue(underTest.bounds)
@@ -594,6 +631,7 @@
         }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun boundsOnQS() =
         testScope.runTest {
             val bounds by collectLastValue(underTest.bounds)
@@ -693,6 +731,7 @@
         }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun translationYUpdatesOnKeyguardForBurnIn() =
         testScope.runTest {
             val translationY by collectLastValue(underTest.translationY(BurnInParameters()))
@@ -726,6 +765,7 @@
         }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun translationYDoesNotUpdateWhenShadeIsExpanded() =
         testScope.runTest {
             val translationY by collectLastValue(underTest.translationY(BurnInParameters()))
@@ -746,6 +786,7 @@
         }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun updateBounds_fromKeyguardRoot() =
         testScope.runTest {
             val bounds by collectLastValue(underTest.bounds)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
index e31cdcd..dc96139 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
@@ -72,7 +72,7 @@
             testScope.runTest {
                 localMediaRepository.updateCurrentConnectedDevice(null)
 
-                val slice by collectLastValue(underTest.ancSlice(1))
+                val slice by collectLastValue(underTest.ancSlice(1, false, false))
                 runCurrent()
 
                 assertThat(slice).isNull()
@@ -86,7 +86,7 @@
             testScope.runTest {
                 localMediaRepository.updateCurrentConnectedDevice(createMediaDevice())
 
-                val slice by collectLastValue(underTest.ancSlice(1))
+                val slice by collectLastValue(underTest.ancSlice(1, false, false))
                 runCurrent()
 
                 assertThat(slice).isNotNull()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
index 53f0bc9..81e6ac4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.testKosmos
 import com.android.systemui.volume.panel.component.anc.FakeSliceFactory
 import com.android.systemui.volume.panel.component.anc.ancSliceRepository
+import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
@@ -57,10 +58,10 @@
                     FakeSliceFactory.createSlice(hasError = true, hasSliceItem = true)
                 )
 
-                val slice by collectLastValue(underTest.ancSlice)
+                val slice by collectLastValue(underTest.ancSlices)
                 runCurrent()
 
-                assertThat(slice).isNull()
+                assertThat(slice).isInstanceOf(AncSlices.Unavailable::class.java)
             }
         }
     }
@@ -74,10 +75,10 @@
                     FakeSliceFactory.createSlice(hasError = false, hasSliceItem = false)
                 )
 
-                val slice by collectLastValue(underTest.ancSlice)
+                val slice by collectLastValue(underTest.ancSlices)
                 runCurrent()
 
-                assertThat(slice).isNull()
+                assertThat(slice).isInstanceOf(AncSlices.Unavailable::class.java)
             }
         }
     }
@@ -91,10 +92,10 @@
                     FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
                 )
 
-                val slice by collectLastValue(underTest.ancSlice)
+                val slice by collectLastValue(underTest.ancSlices)
                 runCurrent()
 
-                assertThat(slice).isNotNull()
+                assertThat(slice).isInstanceOf(AncSlices.Ready::class.java)
             }
         }
     }
diff --git a/packages/SystemUI/res/drawable/ic_noise_aware.xml b/packages/SystemUI/res/drawable/ic_noise_aware.xml
deleted file mode 100644
index 5482641..0000000
--- a/packages/SystemUI/res/drawable/ic_noise_aware.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-  ~ 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.
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="960"
-    android:viewportHeight="960"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M440,82Q450,81 460,80.5Q470,80 480,80Q491,80 500.5,80.5Q510,81 520,82L520,162Q510,160 500.5,160Q491,160 480,160Q469,160 459.5,160Q450,160 440,162L440,82ZM272,138Q289,127 306.5,119Q324,111 343,104L378,176Q358,182 340.5,190.5Q323,199 306,210L272,138ZM654,210Q637,199 619.5,190.5Q602,182 582,176L617,104Q636,111 653.5,119Q671,127 688,138L654,210ZM753,311Q742,294 729,278.5Q716,263 702,249L765,199Q779,213 792,228.5Q805,244 816,261L753,311ZM143,263Q154,246 166.5,230.5Q179,215 193,201L256,251Q242,265 229.5,280.5Q217,296 206,313L143,263ZM83,428Q85,408 90,388.5Q95,369 101,350L180,368Q173,387 168.5,406.5Q164,426 162,446L83,428ZM799,449Q797,429 792.5,409Q788,389 781,370L859,352Q865,371 870,390.5Q875,410 877,430L799,449ZM781,590Q788,571 792,552Q796,533 798,513L877,531Q875,551 870,570.5Q865,590 859,609L781,590ZM162,514Q164,534 168.5,553.5Q173,573 180,592L101,610Q95,591 90,571.5Q85,552 83,532L162,514ZM705,708Q719,694 731,678.5Q743,663 754,646L818,696Q807,713 794.5,728.5Q782,744 768,758L705,708ZM194,760Q180,746 167.5,730Q155,714 144,697L206,647Q217,664 229.5,680Q242,696 256,710L194,760ZM583,783Q603,776 620,768Q637,760 654,749L689,821Q672,832 654.5,840.5Q637,849 618,856L583,783ZM344,857Q325,850 307,841.5Q289,833 272,822L307,750Q324,761 341.5,769.5Q359,778 379,784L344,857ZM480,880Q470,880 460,879.5Q450,879 440,878L440,798Q453,800 480,800Q491,800 500.5,800Q510,800 520,798L520,878Q510,879 500.5,879.5Q491,880 480,880ZM520,720Q482,720 450.5,697Q419,674 406,638Q403,629 399.5,620.5Q396,612 389,605L334,550Q308,524 294,490.5Q280,457 280,420Q280,345 332.5,292.5Q385,240 460,240Q529,240 580,285.5Q631,331 639,400L558,400Q551,365 523.5,342.5Q496,320 460,320Q418,320 389,349Q360,378 360,420Q360,440 368,459.5Q376,479 391,494L445,548Q459,562 467.5,578.5Q476,595 482,612Q487,625 497,632.5Q507,640 520,640Q537,640 548.5,628.5Q560,617 560,600L640,600Q640,650 605.5,685Q571,720 520,720ZM540,560Q515,560 497.5,542.5Q480,525 480,500Q480,474 497.5,457Q515,440 540,440Q566,440 583,457Q600,474 600,500Q600,525 583,542.5Q566,560 540,560Z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/tv_volume_row_seek_thumb.xml b/packages/SystemUI/res/drawable/tv_volume_row_seek_thumb.xml
index 3c31861..a706c65 100644
--- a/packages/SystemUI/res/drawable/tv_volume_row_seek_thumb.xml
+++ b/packages/SystemUI/res/drawable/tv_volume_row_seek_thumb.xml
@@ -19,9 +19,4 @@
     <solid android:color="@color/tv_volume_dialog_accent" />
     <size android:width="@dimen/tv_volume_seek_bar_thumb_diameter"
           android:height="@dimen/tv_volume_seek_bar_thumb_diameter" />
-    <stroke android:width="@dimen/tv_volume_seek_bar_thumb_focus_ring_width"
-            android:color="@color/tv_volume_dialog_seek_thumb_focus_ring"/>
-    <item name="android:shadowColor">@color/tv_volume_dialog_seek_thumb_shadow</item>
-    <item name="android:shadowRadius">@dimen/tv_volume_seek_bar_thumb_shadow_radius</item>
-    <item name="android:shadowDy">@dimen/tv_volume_seek_bar_thumb_shadow_dy</item>
 </shape>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index 52f591f..d3bafbc 100644
--- a/packages/SystemUI/res/values-land-television/dimens.xml
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -28,9 +28,6 @@
   <dimen name="tv_volume_dialog_bubble_size">36dp</dimen>
   <dimen name="tv_volume_dialog_row_padding">6dp</dimen>
   <dimen name="tv_volume_number_text_size">16sp</dimen>
-  <dimen name="tv_volume_seek_bar_thumb_diameter">24dp</dimen>
-  <dimen name="tv_volume_seek_bar_thumb_focus_ring_width">8dp</dimen>
+  <dimen name="tv_volume_seek_bar_thumb_diameter">16dp</dimen>
   <dimen name="tv_volume_icons_size">20dp</dimen>
-  <dimen name="tv_volume_seek_bar_thumb_shadow_radius">4.0</dimen>
-  <dimen name="tv_volume_seek_bar_thumb_shadow_dy">4.0</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 2bab3cb..5d45607 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -28,8 +28,6 @@
 
     <color name="red">#FFCC0000</color>
     <color name="tv_volume_dialog_circle">#08FFFFFF</color>
-    <color name="tv_volume_dialog_seek_thumb_focus_ring">#1AFFFFFF</color>
-    <color name="tv_volume_dialog_seek_thumb_shadow">#40000000</color>
     <color name="tv_volume_dialog_seek_bar_background">#A03C4043</color>
     <color name="tv_volume_dialog_seek_bar_fill">#FFF8F9FA</color>
     <color name="tv_volume_dialog_accent">#FFDADCE0</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b0b5482..af327d2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -2001,4 +2001,7 @@
 
     <!-- SliceView grid gutter for ANC Slice -->
     <dimen name="abc_slice_grid_gutter">0dp</dimen>
+    <!-- SliceView icon size -->
+    <dimen name="abc_slice_big_pic_min_height">64dp</dimen>
+    <dimen name="abc_slice_big_pic_max_height">64dp</dimen>
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 25d7713..c509356 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -83,9 +83,9 @@
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardWmStateRefactor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
@@ -101,6 +101,8 @@
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
 
+import dagger.Lazy;
+
 import java.io.File;
 import java.util.Arrays;
 import java.util.Optional;
@@ -108,7 +110,6 @@
 import javax.inject.Inject;
 import javax.inject.Provider;
 
-import dagger.Lazy;
 import kotlinx.coroutines.Job;
 
 /** Controller for {@link KeyguardSecurityContainer} */
@@ -310,7 +311,7 @@
          */
         @Override
         public void finish(int targetUserId) {
-            if (!mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+            if (!RefactorKeyguardDismissIntent.isEnabled()) {
                 // If there's a pending runnable because the user interacted with a widget
                 // and we're leaving keyguard, then run it.
                 boolean deferKeyguardDone = false;
@@ -649,7 +650,7 @@
      * @param action callback to be invoked when keyguard disappear animation completes.
      */
     public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
-        if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (RefactorKeyguardDismissIntent.isEnabled()) {
             return;
         }
         if (mCancelAction != null) {
@@ -943,7 +944,7 @@
             mUiEventLogger.log(uiEvent, getSessionId());
         }
 
-        if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (RefactorKeyguardDismissIntent.isEnabled()) {
             if (authenticatedWithPrimaryAuth) {
                 mPrimaryBouncerInteractor.get()
                         .notifyKeyguardAuthenticatedPrimaryAuth(targetUserId);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8c51a4e..4987724 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -225,7 +225,7 @@
     protected static final int BIOMETRIC_STATE_STOPPED = 0;
 
     /** Biometric authentication state: Listening. */
-    private static final int BIOMETRIC_STATE_RUNNING = 1;
+    protected static final int BIOMETRIC_STATE_RUNNING = 1;
 
     /**
      * Biometric authentication: Cancelling and waiting for the relevant biometric service to
@@ -1145,7 +1145,6 @@
         if (getUserCanSkipBouncer(userId)) {
             mTrustManager.unlockedByBiometricForUser(userId, FACE);
         }
-        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
         mLogger.d("onFaceAuthenticated");
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1156,6 +1155,12 @@
             }
         }
 
+        // Intentionally update the fingerprint running state after sending the
+        // onBiometricAuthenticated callback to listeners. Updating the fingerprint listening state
+        // can update the state of the device which listeners to the callback may rely on.
+        // For example, the alternate bouncer visibility state or udfps finger down state.
+        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
+
         // Only authenticate face once when assistant is visible
         mAssistantVisible = false;
 
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 3e03fb8..b8af59d 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -401,8 +401,6 @@
         mExecutor = mThreadFactory.buildDelayableExecutorOnHandler(mHandler);
         mExecutor.execute(this::startOnScreenDecorationsThread);
         mDotViewController.setUiExecutor(mExecutor);
-        mJavaAdapter.alwaysCollectFlow(mFacePropertyRepository.getSensorLocation(),
-                this::onFaceSensorLocationChanged);
         mCommandRegistry.registerCommand(ScreenDecorCommand.SCREEN_DECOR_CMD_NAME,
                 () -> new ScreenDecorCommand(mScreenDecorCommandCallback));
     }
@@ -579,6 +577,8 @@
         };
         mDisplayTracker.addDisplayChangeCallback(mDisplayListener, new HandlerExecutor(mHandler));
         updateConfiguration();
+        mJavaAdapter.alwaysCollectFlow(mFacePropertyRepository.getSensorLocation(),
+                this::onFaceSensorLocationChanged);
         Trace.endSection();
     }
 
@@ -1320,10 +1320,18 @@
     @VisibleForTesting
     void onFaceSensorLocationChanged(Point location) {
         mLogger.onSensorLocationChanged();
+
         if (mExecutor != null) {
             mExecutor.execute(
-                    () -> updateOverlayProviderViews(
-                            new Integer[]{mFaceScanningViewId}));
+                    () -> {
+                        if (getOverlayView(mFaceScanningViewId) == null) {
+                            // face sensor location was just initialized
+                            setupDecorations();
+                        } else {
+                            updateOverlayProviderViews(new Integer[]{mFaceScanningViewId});
+                        }
+                    }
+            );
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
index 0f4d63c..7e96e48 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -149,7 +149,7 @@
             if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
                 mValueAnimator.cancel();
             }
-            mController.enableWindowMagnificationInternal(scale, centerX, centerY,
+            mController.updateWindowMagnificationInternal(scale, centerX, centerY,
                     mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
             updateState();
             return;
@@ -159,7 +159,7 @@
 
         if (mEndSpec.equals(mStartSpec)) {
             if (mState == STATE_DISABLED) {
-                mController.enableWindowMagnificationInternal(scale, centerX, centerY,
+                mController.updateWindowMagnificationInternal(scale, centerX, centerY,
                         mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
             } else if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
                 mValueAnimator.cancel();
@@ -306,7 +306,7 @@
         // If the animation is playing backwards, mStartSpec will be the final spec we would
         // like to reach.
         AnimationSpec spec = isReverse ? mStartSpec : mEndSpec;
-        mController.enableWindowMagnificationInternal(
+        mController.updateWindowMagnificationInternal(
                 spec.mScale, spec.mCenterX, spec.mCenterY,
                 mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
 
@@ -358,7 +358,7 @@
                 mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract;
         final float centerY =
                 mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract;
-        mController.enableWindowMagnificationInternal(sentScale, centerX, centerY,
+        mController.updateWindowMagnificationInternal(sentScale, centerX, centerY,
                 mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index d65cd5c..a847c3d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -148,7 +148,7 @@
     /**
      * SourceBound is the bound of the magnified region which projects the magnified content.
      * SourceBound's center is equal to the parameters centerX and centerY in
-     * {@link WindowMagnificationController#enableWindowMagnificationInternal(float, float, float)}}
+     * {@link WindowMagnificationController#updateWindowMagnificationInternal(float, float, float)}}
      * but it is calculated from {@link #mMagnificationFrame}'s center in the runtime.
      */
     private final Rect mSourceBounds = new Rect();
@@ -566,7 +566,7 @@
         // window size changed not caused by rotation.
         if (isActivated() && reCreateWindow) {
             deleteWindowMagnification();
-            enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN);
+            updateWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN);
         }
     }
 
@@ -1317,7 +1317,7 @@
     }
 
     /**
-     * Wraps {@link WindowMagnificationController#enableWindowMagnificationInternal(float, float,
+     * Wraps {@link WindowMagnificationController#updateWindowMagnificationInternal(float, float,
      * float, float, float)}
      * with transition animation. If the window magnification is not enabled, the scale will start
      * from 1.0 and the center won't be changed during the animation. If animator is
@@ -1344,10 +1344,12 @@
     }
 
     /**
-     * Enables window magnification with specified parameters. If the given scale is <strong>less
-     * than or equal to 1.0f</strong>, then
+     * Updates window magnification status with specified parameters. If the given scale is
+     * <strong>less than 1.0f</strong>, then
      * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
-     * be consistent with the behavior of display magnification.
+     * be consistent with the behavior of display magnification. If the given scale is
+     * <strong>larger than or equal to 1.0f</strong>, and the window magnification is not activated
+     * yet, window magnification will be enabled.
      *
      * @param scale   the target scale, or {@link Float#NaN} to leave unchanged
      * @param centerX the screen-relative X coordinate around which to center for magnification,
@@ -1355,16 +1357,17 @@
      * @param centerY the screen-relative Y coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
      */
-    void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
-        enableWindowMagnificationInternal(scale, centerX, centerY, Float.NaN, Float.NaN);
+    void updateWindowMagnificationInternal(float scale, float centerX, float centerY) {
+        updateWindowMagnificationInternal(scale, centerX, centerY, Float.NaN, Float.NaN);
     }
 
     /**
-     * Enables window magnification with specified parameters. If the given scale is <strong>less
-     * than 1.0f</strong>, then
+     * Updates window magnification status with specified parameters. If the given scale is
+     * <strong>less than 1.0f</strong>, then
      * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
-     * be consistent with the behavior of display magnification.
-     *
+     * be consistent with the behavior of display magnification. If the given scale is
+     * <strong>larger than or equal to 1.0f</strong>, and the window magnification is not activated
+     * yet, window magnification will be enabled.
      * @param scale   the target scale, or {@link Float#NaN} to leave unchanged
      * @param centerX the screen-relative X coordinate around which to center for magnification,
      *                or {@link Float#NaN} to leave unchanged.
@@ -1377,7 +1380,7 @@
      *                                       between frame position Y and centerY,
      *                                       or {@link Float#NaN} to leave unchanged.
      */
-    void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
+    void updateWindowMagnificationInternal(float scale, float centerX, float centerY,
                 float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY) {
         if (Float.compare(scale, 1.0f) < 0) {
             deleteWindowMagnification();
@@ -1433,7 +1436,7 @@
             return;
         }
 
-        enableWindowMagnificationInternal(scale, Float.NaN, Float.NaN);
+        updateWindowMagnificationInternal(scale, Float.NaN, Float.NaN);
         mHandler.removeCallbacks(mUpdateStateDescriptionRunnable);
         mHandler.postDelayed(mUpdateStateDescriptionRunnable, UPDATE_STATE_DESCRIPTION_DELAY_MS);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
index 7d67219..591da40 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import android.content.res.Configuration
-import android.view.Display
 import com.android.systemui.biometrics.data.repository.DisplayStateRepository
 import com.android.systemui.biometrics.shared.model.DisplayRotation
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
@@ -28,7 +27,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
 import com.android.systemui.unfold.updates.FoldProvider
-import com.android.systemui.util.kotlin.sample
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -36,8 +34,6 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
 /** Aggregates display state information. */
@@ -129,16 +125,7 @@
         screenSizeFoldProvider.onConfigurationChange(newConfig)
     }
 
-    private val defaultDisplay =
-        displayRepository.displays.map { displays ->
-            displays.firstOrNull { it.displayId == Display.DEFAULT_DISPLAY }
-        }
-
-    override val isDefaultDisplayOff =
-        displayRepository.displayChangeEvent
-            .filter { it == Display.DEFAULT_DISPLAY }
-            .sample(defaultDisplay)
-            .map { it?.state == Display.STATE_OFF }
+    override val isDefaultDisplayOff = displayRepository.defaultDisplayOff
 
     override val isLargeScreen: Flow<Boolean> = displayStateRepository.isLargeScreen
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 76d46ed..072fe47 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -463,6 +463,23 @@
                         }
                     }
                 }
+
+                // Retry and confirmation when finger on sensor
+                launch {
+                    combine(
+                            viewModel.canTryAgainNow,
+                            viewModel.hasFingerOnSensor,
+                            viewModel.isPendingConfirmation,
+                            ::Triple
+                        )
+                        .collect { (canRetry, fingerAcquired, pendingConfirmation) ->
+                            if (canRetry && fingerAcquired) {
+                                legacyCallback.onButtonTryAgain()
+                            } else if (pendingConfirmation && fingerAcquired) {
+                                viewModel.confirmAuthenticated()
+                            }
+                        }
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 21ebff4..4e9acbd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -22,6 +22,7 @@
 import android.graphics.Rect
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
+import android.hardware.biometrics.BiometricFingerprintConstants
 import android.hardware.biometrics.BiometricPrompt
 import android.hardware.biometrics.Flags.customBiometricPrompt
 import android.hardware.biometrics.PromptContentView
@@ -32,6 +33,7 @@
 import com.android.systemui.Flags.constraintBp
 import com.android.systemui.biometrics.UdfpsUtils
 import com.android.systemui.biometrics.Utils
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
 import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
@@ -40,6 +42,7 @@
 import com.android.systemui.biometrics.shared.model.DisplayRotation
 import com.android.systemui.biometrics.shared.model.PromptKind
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
 import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlinx.coroutines.Job
@@ -66,6 +69,7 @@
     promptSelectorInteractor: PromptSelectorInteractor,
     @Application private val context: Context,
     private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
+    private val biometricStatusInteractor: BiometricStatusInteractor,
     private val udfpsUtils: UdfpsUtils
 ) {
     /** The set of modalities available for this prompt */
@@ -185,6 +189,24 @@
     /** Fingerprint sensor state. */
     val fingerprintStartMode: Flow<FingerprintStartMode> = _fingerprintStartMode.asStateFlow()
 
+    /** Whether a finger has been acquired by the sensor */
+    // TODO(b/331948073): Add support for detecting SFPS finger without authentication running
+    val hasFingerBeenAcquired: Flow<Boolean> =
+        combine(biometricStatusInteractor.fingerprintAcquiredStatus, modalities) {
+                status,
+                modalities ->
+                modalities.hasSfps &&
+                    status is AcquiredFingerprintAuthenticationStatus &&
+                    status.acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START
+            }
+            .distinctUntilChanged()
+
+    /** Whether there is currently a finger on the sensor */
+    val hasFingerOnSensor: Flow<Boolean> =
+        combine(hasFingerBeenAcquired, _isOverlayTouched) { hasFingerBeenAcquired, overlayTouched ->
+            hasFingerBeenAcquired || overlayTouched
+        }
+
     private val _forceLargeSize = MutableStateFlow(false)
     private val _forceMediumSize = MutableStateFlow(false)
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 4d328d6..5a174b9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.CommunalTransitionKeys
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
@@ -70,9 +71,9 @@
         keyguardTransitionInteractor.startedKeyguardTransitionStep
             .mapLatest(::determineSceneAfterTransition)
             .filterNotNull()
-            // TODO(b/322787129): Also set a custom transition animation here to avoid the regular
-            // slide-in animation when setting the scene programmatically
-            .onEach { nextScene -> communalInteractor.changeScene(nextScene) }
+            .onEach { nextScene ->
+                communalInteractor.changeScene(nextScene, CommunalTransitionKeys.SimpleFade)
+            }
             .launchIn(applicationScope)
 
         // TODO(b/322787129): re-enable once custom animations are in place
@@ -143,7 +144,14 @@
         val docked = dockManager.isDocked
 
         return when {
-            docked && to == KeyguardState.LOCKSCREEN && from == KeyguardState.DREAMING -> {
+            to == KeyguardState.OCCLUDED -> {
+                // Hide communal when an activity is started on keyguard, to ensure the activity
+                // underneath the hub is shown.
+                CommunalScenes.Blank
+            }
+            to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> {
+                // When transitioning to the hub from an occluded state, fade out the hub without
+                // doing any translation.
                 CommunalScenes.Communal
             }
             to == KeyguardState.GONE -> CommunalScenes.Blank
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 246d5d9..ac8e5e8 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -44,6 +44,8 @@
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dock.DockManager
+import com.android.systemui.dock.retrieveIsDocked
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
@@ -103,6 +105,7 @@
     private val userTracker: UserTracker,
     private val activityStarter: ActivityStarter,
     private val userManager: UserManager,
+    private val dockManager: DockManager,
     sceneInteractor: SceneInteractor,
     sceneContainerFlags: SceneContainerFlags,
     @CommunalLog logBuffer: LogBuffer,
@@ -123,7 +126,7 @@
         and(
                 communalSettingsInteractor.isCommunalEnabled,
                 not(keyguardInteractor.isEncryptedOrLockdown),
-                or(keyguardInteractor.isKeyguardVisible, keyguardInteractor.isDreaming)
+                or(keyguardInteractor.isKeyguardShowing, keyguardInteractor.isDreaming)
             )
             .distinctUntilChanged()
             .onEach { available ->
@@ -143,6 +146,9 @@
                 replay = 1,
             )
 
+    /** Whether to show communal by default */
+    val showByDefault: Flow<Boolean> = and(isCommunalAvailable, dockManager.retrieveIsDocked())
+
     /**
      * Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].
      *
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
new file mode 100644
index 0000000..a3c61a4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.systemui.communal.shared.model
+
+import com.android.compose.animation.scene.TransitionKey
+
+/**
+ * Defines all known named transitions for [CommunalScenes].
+ *
+ * These transitions can be referenced by key when changing scenes programmatically.
+ */
+object CommunalTransitionKeys {
+    /** Fades the glanceable hub without any translation */
+    val SimpleFade = TransitionKey("SimpleFade")
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
index 96e4b34..bdf4e72 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
@@ -16,7 +16,11 @@
 
 package com.android.systemui.communal.ui.viewmodel
 
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
@@ -25,6 +29,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.merge
 
 /** View model for transitions related to the communal hub. */
@@ -37,6 +42,8 @@
     lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel,
     dreamToGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
     glanceableHubToDreamTransitionViewModel: GlanceableHubToDreamingTransitionViewModel,
+    communalInteractor: CommunalInteractor,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
 ) {
     /**
      * Whether UMO location should be on communal. This flow is responsive to transitions so that a
@@ -51,4 +58,14 @@
                 glanceableHubToDreamTransitionViewModel.showUmo,
             )
             .distinctUntilChanged()
+
+    /** Whether to show communal by default */
+    val showByDefault: Flow<Boolean> = communalInteractor.showByDefault
+
+    val transitionFromOccludedEnded =
+        keyguardTransitionInteractor.transitionStepsFromState(KeyguardState.OCCLUDED).filter { step
+            ->
+            step.transitionState == TransitionState.FINISHED ||
+                step.transitionState == TransitionState.CANCELED
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
index 0e04d15..baae986 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
 import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.BiometricType
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
@@ -312,7 +313,11 @@
         // or device starts going to sleep.
         merge(
                 powerInteractor.isAsleep,
-                keyguardTransitionInteractor.isInTransitionToState(KeyguardState.GONE),
+                if (KeyguardWmStateRefactor.isEnabled) {
+                    keyguardTransitionInteractor.isInTransitionToState(KeyguardState.GONE)
+                } else {
+                    keyguardRepository.keyguardDoneAnimationsFinished.map { true }
+                },
                 userRepository.selectedUser.map {
                     it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS
                 },
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 1230156..4ac0c56 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -42,6 +42,7 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.filterIsInstance
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
@@ -67,6 +68,9 @@
      */
     val pendingDisplay: Flow<PendingDisplay?>
 
+    /** Whether the default display is currently off. */
+    val defaultDisplayOff: Flow<Boolean>
+
     /** Represents a connected display that has not been enabled yet. */
     interface PendingDisplay {
         /** Id of the pending display. */
@@ -290,6 +294,11 @@
             }
             .debugLog("pendingDisplay")
 
+    override val defaultDisplayOff: Flow<Boolean> =
+        displays
+            .map { displays -> displays.firstOrNull { it.displayId == Display.DEFAULT_DISPLAY } }
+            .map { it?.state == Display.STATE_OFF }
+
     private fun <T> Flow<T>.debugLog(flowName: String): Flow<T> {
         return if (DEBUG) {
             traceEach(flowName, logcat = true, traceEmissionCount = true)
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt
index 037c23b..ac03463 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
@@ -28,6 +29,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.kotlin.FlowDumperImpl
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -49,7 +51,8 @@
     private val communalInteractor: CommunalInteractor,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val userTracker: UserTracker,
-) {
+    dumpManager: DumpManager,
+) : FlowDumperImpl(dumpManager) {
 
     fun startTransitionFromDream() {
         val showGlanceableHub =
@@ -83,6 +86,7 @@
                 toGlanceableHubTransitionViewModel.dreamAlpha,
             )
             .distinctUntilChanged()
+            .dumpWhileCollecting("dreamAlpha")
 
     val dreamOverlayAlpha: Flow<Float> =
         merge(
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 640534c..612ae6c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -153,11 +153,6 @@
     // TODO(b/267722622): Tracking Bug
     @JvmField val WALLPAPER_PICKER_UI_FOR_AIWP = releasedFlag("wallpaper_picker_ui_for_aiwp")
 
-    /** Whether to use a new data source for intents to run on keyguard dismissal. */
-    // TODO(b/275069969): Tracking bug.
-    @JvmField
-    val REFACTOR_KEYGUARD_DISMISS_INTENT = unreleasedFlag("refactor_keyguard_dismiss_intent")
-
     /** Whether to allow long-press on the lock screen to directly open wallpaper picker. */
     // TODO(b/277220285): Tracking bug.
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 654610e..2a9dad0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -137,6 +137,7 @@
 import com.android.systemui.animation.TransitionAnimator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
@@ -584,7 +585,7 @@
 
     private CentralSurfaces mCentralSurfaces;
 
-    private IRemoteAnimationFinishedCallback mUnoccludeFromDreamFinishedCallback;
+    private IRemoteAnimationFinishedCallback mUnoccludeFinishedCallback;
 
     private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
             new DeviceConfig.OnPropertiesChangedListener() {
@@ -1234,10 +1235,12 @@
                             mUnoccludeAnimator.cancel();
                         }
 
-                        if (isDream) {
+                        if (isDream || mShowCommunalByDefault) {
                             initAlphaForAnimationTargets(wallpapers);
-                            mDreamViewModel.get().startTransitionFromDream();
-                            mUnoccludeFromDreamFinishedCallback = finishedCallback;
+                            if (isDream) {
+                                mDreamViewModel.get().startTransitionFromDream();
+                            }
+                            mUnoccludeFinishedCallback = finishedCallback;
                             return;
                         }
 
@@ -1304,7 +1307,10 @@
 
     private Consumer<Float> getRemoteSurfaceAlphaApplier() {
         return (Float alpha) -> {
-            if (mRemoteAnimationTarget == null) return;
+            if (mRemoteAnimationTarget == null) {
+                Log.e(TAG, "Attempting to set alpha on null animation target");
+                return;
+            }
             final View localView = mKeyguardViewControllerLazy.get().getViewRootImpl().getView();
             final SyncRtSurfaceTransactionApplier applier =
                     new SyncRtSurfaceTransactionApplier(localView);
@@ -1319,10 +1325,10 @@
 
     private Consumer<TransitionStep> getFinishedCallbackConsumer() {
         return (TransitionStep step) -> {
-            if (mUnoccludeFromDreamFinishedCallback == null) return;
+            if (mUnoccludeFinishedCallback == null) return;
             try {
-                mUnoccludeFromDreamFinishedCallback.onAnimationFinished();
-                mUnoccludeFromDreamFinishedCallback = null;
+                mUnoccludeFinishedCallback.onAnimationFinished();
+                mUnoccludeFinishedCallback = null;
             } catch (RemoteException e) {
                 Log.e(TAG, "Wasn't able to callback", e);
             }
@@ -1365,7 +1371,9 @@
     private final SessionTracker mSessionTracker;
     private final CoroutineDispatcher mMainDispatcher;
     private final Lazy<DreamViewModel> mDreamViewModel;
+    private final Lazy<CommunalTransitionViewModel> mCommunalTransitionViewModel;
     private RemoteAnimationTarget mRemoteAnimationTarget;
+    private Boolean mShowCommunalByDefault;
 
     private final Lazy<WindowManagerLockscreenVisibilityManager> mWmLockscreenVisibilityManager;
 
@@ -1414,6 +1422,7 @@
             SystemClock systemClock,
             @Main CoroutineDispatcher mainDispatcher,
             Lazy<DreamViewModel> dreamViewModel,
+            Lazy<CommunalTransitionViewModel> communalTransitionViewModel,
             SystemPropertiesHelper systemPropertiesHelper,
             Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
             SelectedUserInteractor selectedUserInteractor,
@@ -1485,6 +1494,7 @@
         mSessionTracker = sessionTracker;
 
         mDreamViewModel = dreamViewModel;
+        mCommunalTransitionViewModel = communalTransitionViewModel;
         mWmLockscreenVisibilityManager = wmLockscreenVisibilityManager;
         mMainDispatcher = mainDispatcher;
 
@@ -1615,11 +1625,21 @@
 
             ViewRootImpl viewRootImpl = mKeyguardViewControllerLazy.get().getViewRootImpl();
             if (viewRootImpl != null) {
-                final DreamViewModel viewModel = mDreamViewModel.get();
-                collectFlow(viewRootImpl.getView(), viewModel.getDreamAlpha(),
+                final DreamViewModel dreamViewModel = mDreamViewModel.get();
+                final CommunalTransitionViewModel communalViewModel =
+                        mCommunalTransitionViewModel.get();
+                collectFlow(viewRootImpl.getView(), dreamViewModel.getDreamAlpha(),
                         getRemoteSurfaceAlphaApplier(), mMainDispatcher);
-                collectFlow(viewRootImpl.getView(), viewModel.getTransitionEnded(),
+                collectFlow(viewRootImpl.getView(), dreamViewModel.getTransitionEnded(),
                         getFinishedCallbackConsumer(), mMainDispatcher);
+                collectFlow(viewRootImpl.getView(), communalViewModel.getShowByDefault(),
+                        (showByDefault) ->
+                                mShowCommunalByDefault = showByDefault, mMainDispatcher);
+                collectFlow(viewRootImpl.getView(),
+                        communalViewModel.getTransitionFromOccludedEnded(),
+                        getFinishedCallbackConsumer(), mMainDispatcher);
+            } else {
+                Log.e(TAG, "Keyguard ViewRootImpl is null");
             }
         }
         // Most services aren't available until the system reaches the ready state, so we
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index a243b8e..7879ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -39,6 +39,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingModule;
+import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -161,6 +162,7 @@
             SystemClock systemClock,
             @Main CoroutineDispatcher mainDispatcher,
             Lazy<DreamViewModel> dreamViewModel,
+            Lazy<CommunalTransitionViewModel> communalTransitionViewModel,
             SystemPropertiesHelper systemPropertiesHelper,
             Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
             SelectedUserInteractor selectedUserInteractor,
@@ -208,6 +210,7 @@
                 systemClock,
                 mainDispatcher,
                 dreamViewModel,
+                communalTransitionViewModel,
                 systemPropertiesHelper,
                 wmLockscreenVisibilityManager,
                 selectedUserInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index b6289d4..ee589f4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -87,12 +87,12 @@
             scope.launch {
                 keyguardOcclusionInteractor.isShowWhenLockedActivityOnTop
                     .filterRelevantKeyguardStateAnd { onTop -> !onTop }
-                    .sample(communalInteractor.isIdleOnCommunal, ::Pair)
-                    .collect { (_, isIdleOnCommunal) ->
+                    .sample(communalInteractor.isIdleOnCommunal, communalInteractor.showByDefault)
+                    .collect { (_, isIdleOnCommunal, showCommunalByDefault) ->
                         // Occlusion signals come from the framework, and should interrupt any
                         // existing transition
                         val to =
-                            if (isIdleOnCommunal) {
+                            if (isIdleOnCommunal || showCommunalByDefault) {
                                 KeyguardState.GLANCEABLE_HUB
                             } else {
                                 KeyguardState.LOCKSCREEN
@@ -106,15 +106,16 @@
                     .sample(
                         keyguardInteractor.isKeyguardShowing,
                         communalInteractor.isIdleOnCommunal,
+                        communalInteractor.showByDefault,
                     )
-                    .filterRelevantKeyguardStateAnd { (isOccluded, isShowing, _) ->
+                    .filterRelevantKeyguardStateAnd { (isOccluded, isShowing, _, _) ->
                         !isOccluded && isShowing
                     }
-                    .collect { (_, _, isIdleOnCommunal) ->
+                    .collect { (_, _, isIdleOnCommunal, showCommunalByDefault) ->
                         // Occlusion signals come from the framework, and should interrupt any
                         // existing transition
                         val to =
-                            if (isIdleOnCommunal) {
+                            if (isIdleOnCommunal || showCommunalByDefault) {
                                 KeyguardState.GLANCEABLE_HUB
                             } else {
                                 KeyguardState.LOCKSCREEN
@@ -175,6 +176,7 @@
             duration =
                 when (toState) {
                     KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
+                    KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION
                     else -> DEFAULT_DURATION
                 }.inWholeMilliseconds
         }
@@ -184,6 +186,7 @@
         const val TAG = "FromOccludedTransitionInteractor"
         private val DEFAULT_DURATION = 500.milliseconds
         val TO_LOCKSCREEN_DURATION = 933.milliseconds
+        val TO_GLANCEABLE_HUB_DURATION = 250.milliseconds
         val TO_AOD_DURATION = DEFAULT_DURATION
         val TO_DOZING_DURATION = DEFAULT_DURATION
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt
new file mode 100644
index 0000000..a43eb71
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.systemui.keyguard.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the refactor_keyguard_dismiss_intent flag. */
+@Suppress("NOTHING_TO_INLINE")
+object RefactorKeyguardDismissIntent {
+    /** The aconfig flag name */
+    const val FLAG_NAME = Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT
+
+    /** A token used for dependency declaration */
+    val token: FlagToken
+        get() = FlagToken(FLAG_NAME, isEnabled)
+
+    /** Is the refactor enabled */
+    @JvmStatic
+    inline val isEnabled
+        get() = Flags.refactorKeyguardDismissIntent()
+
+    /**
+     * Called to ensure code is only run when the flag is enabled. This protects users from the
+     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+     * build to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+    /**
+     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+     * the flag is enabled to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
index d5add61..93b3ba5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
@@ -19,9 +19,8 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
+import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
@@ -38,11 +37,10 @@
     private val interactor: KeyguardDismissActionInteractor,
     @Application private val scope: CoroutineScope,
     private val keyguardLogger: KeyguardLogger,
-    private val featureFlags: FeatureFlagsClassic,
 ) : CoreStartable {
 
     override fun start() {
-        if (!featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (!RefactorKeyguardDismissIntent.isEnabled) {
             return
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
index 87d8164..f77d012 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
@@ -21,8 +21,8 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissInteractor
+import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
 import com.android.systemui.keyguard.shared.model.KeyguardDone
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
@@ -44,7 +44,7 @@
 ) : CoreStartable {
 
     override fun start() {
-        if (!featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (!RefactorKeyguardDismissIntent.isEnabled) {
             return
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
index 49ae35a..88d9074 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
@@ -32,7 +32,7 @@
 
     @JvmStatic
     fun bind(
-        context: Context,
+        previewContext: Context,
         smartspace: View,
         splitShadePreview: Boolean,
         viewModel: KeyguardPreviewSmartspaceViewModel,
@@ -46,10 +46,12 @@
                                 SettingsClockSize.DYNAMIC ->
                                     viewModel.getLargeClockSmartspaceTopPadding(
                                         splitShadePreview,
+                                        previewContext,
                                     )
                                 SettingsClockSize.SMALL ->
                                     viewModel.getSmallClockSmartspaceTopPadding(
                                         splitShadePreview,
+                                        previewContext,
                                     )
                             }
                         smartspace.setTopPadding(topPadding)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index ce1aed0..40ea445 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -327,9 +327,12 @@
         smartSpaceView = lockscreenSmartspaceController.buildAndConnectDateView(parentView)
 
         val topPadding: Int =
-            smartspaceViewModel.getLargeClockSmartspaceTopPadding(previewInSplitShade())
-        val startPadding: Int = smartspaceViewModel.getSmartspaceStartPadding()
-        val endPadding: Int = smartspaceViewModel.getSmartspaceEndPadding()
+            smartspaceViewModel.getLargeClockSmartspaceTopPadding(
+                previewInSplitShade(),
+                previewContext,
+            )
+        val startPadding: Int = smartspaceViewModel.getSmartspaceStartPadding(previewContext)
+        val endPadding: Int = smartspaceViewModel.getSmartspaceEndPadding(previewContext)
 
         smartSpaceView?.let {
             it.setPaddingRelative(startPadding, topPadding, endPadding, 0)
@@ -411,7 +414,7 @@
             setUpClock(previewContext, rootView)
             if (MigrateClocksToBlueprint.isEnabled) {
                 KeyguardPreviewClockViewBinder.bind(
-                    context,
+                    previewContext,
                     keyguardRootView,
                     clockViewModel,
                     ::updateClockAppearance
@@ -429,7 +432,7 @@
 
         smartSpaceView?.let {
             KeyguardPreviewSmartspaceViewBinder.bind(
-                context,
+                previewContext,
                 it,
                 previewInSplitShade(),
                 smartspaceViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
index fe88b81..6d0f96c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
@@ -18,9 +18,8 @@
 
 import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
+import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
 import com.android.systemui.keyguard.shared.model.ScrimAlpha
@@ -44,13 +43,12 @@
     private val statusBarStateController: SysuiStatusBarStateController,
     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
     private val keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
-    private val featureFlags: FeatureFlagsClassic,
     private val shadeInteractor: ShadeInteractor,
     private val animationFlow: KeyguardTransitionAnimationFlow,
 ) {
     /** Common fade for scrim alpha values during *BOUNCER->GONE */
     fun scrimAlpha(duration: Duration, fromState: KeyguardState): Flow<ScrimAlpha> {
-        return if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        return if (RefactorKeyguardDismissIntent.isEnabled) {
             keyguardDismissActionInteractor
                 .get()
                 .willAnimateDismissActionOnLockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
index 4f2c6f5..7300152 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
@@ -16,13 +16,10 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import android.content.Context
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.shared.model.SettingsClockSize
 import com.android.systemui.plugins.clocks.ClockController
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.map
@@ -31,9 +28,7 @@
 class KeyguardPreviewClockViewModel
 @Inject
 constructor(
-    @Application private val context: Context,
     interactor: KeyguardClockInteractor,
-    @Application private val applicationScope: CoroutineScope,
 ) {
 
     var shouldHighlightSelectedAffordance: Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt
index b57e3ec..528b14c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import android.content.Context
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.shared.model.SettingsClockSize
 import com.android.systemui.res.R
@@ -31,7 +30,6 @@
 class KeyguardPreviewSmartspaceViewModel
 @Inject
 constructor(
-    @Application private val context: Context,
     interactor: KeyguardClockInteractor,
     val smartspaceViewModel: KeyguardSmartspaceViewModel,
     val clockViewModel: KeyguardClockViewModel,
@@ -55,29 +53,29 @@
                 }
             }
 
-    fun getSmartspaceStartPadding(): Int {
+    fun getSmartspaceStartPadding(context: Context): Int {
         return KeyguardSmartspaceViewModel.getSmartspaceStartMargin(context)
     }
 
-    fun getSmartspaceEndPadding(): Int {
+    fun getSmartspaceEndPadding(context: Context): Int {
         return KeyguardSmartspaceViewModel.getSmartspaceEndMargin(context)
     }
 
-    fun getSmallClockSmartspaceTopPadding(splitShadePreview: Boolean): Int {
-        return getSmallClockTopPadding(splitShadePreview) +
+    fun getSmallClockSmartspaceTopPadding(splitShadePreview: Boolean, context: Context): Int {
+        return getSmallClockTopPadding(splitShadePreview, context) +
             context.resources.getDimensionPixelSize(
                 com.android.systemui.customization.R.dimen.small_clock_height
             )
     }
 
-    fun getLargeClockSmartspaceTopPadding(splitShadePreview: Boolean): Int {
-        return getSmallClockTopPadding(splitShadePreview)
+    fun getLargeClockSmartspaceTopPadding(splitShadePreview: Boolean, context: Context): Int {
+        return getSmallClockTopPadding(splitShadePreview, context)
     }
 
     /*
      * SmallClockTopPadding decides the top position of smartspace
      */
-    private fun getSmallClockTopPadding(splitShadePreview: Boolean): Int {
+    private fun getSmallClockTopPadding(splitShadePreview: Boolean, context: Context): Int {
         return with(context.resources) {
             if (splitShadePreview) {
                 getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index a09d58a..3a19780 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -21,21 +21,15 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import com.android.systemui.res.R
-import com.android.systemui.util.kotlin.pairwise
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.merge
 
 /**
  * Breaks down OCCLUDED->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -49,8 +43,6 @@
     deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     configurationInteractor: ConfigurationInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
-    keyguardInteractor: KeyguardInteractor,
-    keyguardTransitionInteractor: KeyguardTransitionInteractor,
 ) : DeviceEntryIconTransition {
 
     private val transitionAnimation =
@@ -82,28 +74,11 @@
 
     /** Lockscreen views alpha */
     val lockscreenAlpha: Flow<Float> =
-        merge(
-            transitionAnimation.sharedFlow(
-                startTime = 233.milliseconds,
-                duration = 250.milliseconds,
-                onStep = { it },
-                name = "OCCLUDED->LOCKSCREEN: lockscreenAlpha",
-            ),
-            // Required to fix a bug where the shade expands while lockscreenAlpha=1f, due to a call
-            // to setOccluded(false) triggering a reset() call in KeyguardViewMediator. The
-            // permanent solution is to only expand the shade once the keyguard transition from
-            // OCCLUDED starts, but that requires more refactoring of expansion amounts. For now,
-            // emit alpha = 0f for OCCLUDED -> LOCKSCREEN whenever isOccluded flips from true to
-            // false while currentState == OCCLUDED, so that alpha = 0f when that expansion occurs.
-            // TODO(b/332946323): Remove this once it's no longer needed.
-            keyguardInteractor.isKeyguardOccluded
-                .pairwise()
-                .filter { (wasOccluded, isOccluded) ->
-                    wasOccluded &&
-                        !isOccluded &&
-                        keyguardTransitionInteractor.getCurrentState() == KeyguardState.OCCLUDED
-                }
-                .map { 0f }
+        transitionAnimation.sharedFlow(
+            startTime = 233.milliseconds,
+            duration = 250.milliseconds,
+            onStep = { it },
+            name = "OCCLUDED->LOCKSCREEN: lockscreenAlpha",
         )
 
     val deviceEntryBackgroundViewAlpha: Flow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 0587826..a08a234 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -18,10 +18,9 @@
 
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
+import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.shared.model.ScrimAlpha
@@ -46,7 +45,6 @@
     private val statusBarStateController: SysuiStatusBarStateController,
     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
     keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
-    featureFlags: FeatureFlagsClassic,
     bouncerToGoneFlows: BouncerToGoneFlows,
     animationFlow: KeyguardTransitionAnimationFlow,
 ) {
@@ -82,7 +80,7 @@
 
     /** Bouncer container alpha */
     val bouncerAlpha: Flow<Float> =
-        if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (RefactorKeyguardDismissIntent.isEnabled) {
             keyguardDismissActionInteractor
                 .get()
                 .willAnimateDismissActionOnLockscreen
@@ -106,7 +104,7 @@
 
     /** Lockscreen alpha */
     val lockscreenAlpha: Flow<Float> =
-        if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (RefactorKeyguardDismissIntent.isEnabled) {
             keyguardDismissActionInteractor
                 .get()
                 .willAnimateDismissActionOnLockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index 899b9ed..ca898e6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -118,8 +118,9 @@
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.surfaceeffects.PaintDrawCallback;
 import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect;
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState;
+import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.AnimationState;
 import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView;
 import com.android.systemui.surfaceeffects.ripple.MultiRippleController;
 import com.android.systemui.surfaceeffects.ripple.MultiRippleView;
@@ -264,15 +265,15 @@
     private boolean mWasPlaying = false;
     private boolean mButtonClicked = false;
 
-    private final LoadingEffect.Companion.PaintDrawCallback mNoiseDrawCallback =
-            new LoadingEffect.Companion.PaintDrawCallback() {
+    private final PaintDrawCallback mNoiseDrawCallback =
+            new PaintDrawCallback() {
                 @Override
-                public void onDraw(@NonNull Paint loadingPaint) {
-                    mMediaViewHolder.getLoadingEffectView().draw(loadingPaint);
+                public void onDraw(@NonNull Paint paint) {
+                    mMediaViewHolder.getLoadingEffectView().draw(paint);
                 }
             };
-    private final LoadingEffect.Companion.AnimationStateChangedCallback mStateChangedCallback =
-            new LoadingEffect.Companion.AnimationStateChangedCallback() {
+    private final LoadingEffect.AnimationStateChangedCallback mStateChangedCallback =
+            new LoadingEffect.AnimationStateChangedCallback() {
                 @Override
                 public void onStateChanged(@NonNull AnimationState oldState,
                         @NonNull AnimationState newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index adee7f2c..4db89d1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -1200,9 +1200,7 @@
     }
 
     boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
-        return (isPlayBackInfoLocal()
-                || device.getDeviceType() != MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE)
-                && !device.isVolumeFixed();
+        return !device.isVolumeFixed();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
index 3e9b546..2dbe2aa 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
@@ -18,7 +18,9 @@
 
 import android.annotation.ColorInt
 import android.annotation.UserIdInt
+import android.app.ActivityManager.RecentTaskInfo
 import android.content.ComponentName
+import com.android.wm.shell.util.SplitBounds
 
 data class RecentTask(
     val taskId: Int,
@@ -29,7 +31,25 @@
     @ColorInt val colorBackground: Int?,
     val isForegroundTask: Boolean,
     val userType: UserType,
+    val splitBounds: SplitBounds?,
 ) {
+    constructor(
+        taskInfo: RecentTaskInfo,
+        isForegroundTask: Boolean,
+        userType: UserType,
+        splitBounds: SplitBounds? = null
+    ) : this(
+        taskInfo.taskId,
+        taskInfo.displayId,
+        taskInfo.userId,
+        taskInfo.topActivity,
+        taskInfo.baseIntent?.component,
+        taskInfo.taskDescription?.backgroundColor,
+        isForegroundTask,
+        userType,
+        splitBounds
+    )
+
     enum class UserType {
         STANDARD,
         WORK,
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
index a6049c8..596c18f 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
@@ -58,20 +58,27 @@
             val foregroundTaskId1 = foregroundGroup?.taskInfo1?.taskId
             val foregroundTaskId2 = foregroundGroup?.taskInfo2?.taskId
             val foregroundTaskIds = listOfNotNull(foregroundTaskId1, foregroundTaskId2)
-            groupedTasks
-                .flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) }
-                .map {
+            groupedTasks.flatMap {
+                val task1 =
                     RecentTask(
-                        it.taskId,
-                        it.displayId,
-                        it.userId,
-                        it.topActivity,
-                        it.baseIntent?.component,
-                        it.taskDescription?.backgroundColor,
-                        isForegroundTask = it.taskId in foregroundTaskIds && it.isVisible,
-                        userType = userManager.getUserInfo(it.userId).toUserType(),
+                        it.taskInfo1,
+                        it.taskInfo1.taskId in foregroundTaskIds && it.taskInfo1.isVisible,
+                        userManager.getUserInfo(it.taskInfo1.userId).toUserType(),
+                        it.splitBounds
                     )
-                }
+
+                val task2 =
+                    if (it.taskInfo2 != null) {
+                        RecentTask(
+                            it.taskInfo2!!,
+                            it.taskInfo2!!.taskId in foregroundTaskIds && it.taskInfo2!!.isVisible,
+                            userManager.getUserInfo(it.taskInfo2!!.userId).toUserType(),
+                            it.splitBounds
+                        )
+                    } else null
+
+                listOfNotNull(task1, task2)
+            }
         }
 
     private suspend fun RecentTasks.getTasks(): List<GroupedRecentTaskInfo> =
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
index 7c7efd0..9549ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
@@ -24,9 +24,12 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.window.RemoteTransition
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.android.systemui.Flags.pssAppSelectorAbruptExitFix
+import com.android.systemui.Flags.pssAppSelectorRecentsSplitScreen
+import com.android.systemui.display.naturalBounds
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
@@ -34,6 +37,11 @@
 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
 import com.android.systemui.res.R
 import com.android.systemui.util.recycler.HorizontalSpacerItemDecoration
+import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
+import com.android.wm.shell.splitscreen.SplitScreen
+import com.android.wm.shell.util.SplitBounds
+import java.util.Optional
 import javax.inject.Inject
 
 /**
@@ -48,6 +56,7 @@
     private val taskViewSizeProvider: TaskPreviewSizeProvider,
     private val activityTaskManager: IActivityTaskManager,
     private val resultHandler: MediaProjectionAppSelectorResultHandler,
+    private val splitScreen: Optional<SplitScreen>,
 ) : RecentTaskClickListener, TaskPreviewSizeListener {
 
     private var views: Views? = null
@@ -63,11 +72,11 @@
     fun createView(parent: ViewGroup): ViewGroup =
         views?.root
             ?: createRecentViews(parent)
-                .also {
-                    views = it
-                    lastBoundData?.let { recents -> bind(recents) }
-                }
-                .root
+                    .also {
+                        views = it
+                        lastBoundData?.let { recents -> bind(recents) }
+                    }
+                    .root
 
     fun bind(recentTasks: List<RecentTask>) {
         views?.apply {
@@ -93,8 +102,10 @@
     private fun createRecentViews(parent: ViewGroup): Views {
         val recentsRoot =
             LayoutInflater.from(parent.context)
-                .inflate(R.layout.media_projection_recent_tasks, parent, /* attachToRoot= */ false)
-                as ViewGroup
+                    .inflate(R.layout.media_projection_recent_tasks,
+                        parent, /* attachToRoot= */
+                        false)
+                    as ViewGroup
 
         val container =
             recentsRoot.requireViewById<View>(R.id.media_projection_recent_tasks_container)
@@ -121,18 +132,34 @@
         return Views(recentsRoot, container, progress, recycler)
     }
 
+    private fun RecentTask.isLaunchingInSplitScreen(): Boolean {
+        return splitScreen.isPresent && splitBounds != null
+    }
+
     override fun onRecentAppClicked(task: RecentTask, view: View) {
         val launchCookie = LaunchCookie()
         val activityOptions = createAnimation(task, view)
         activityOptions.pendingIntentBackgroundActivityStartMode =
             MODE_BACKGROUND_ACTIVITY_START_ALLOWED
-        activityOptions.setLaunchCookie(launchCookie)
         activityOptions.launchDisplayId = task.displayId
+        activityOptions.setLaunchCookie(launchCookie)
 
-        activityTaskManager.startActivityFromRecents(task.taskId, activityOptions.toBundle())
-        resultHandler.returnSelectedApp(launchCookie)
+        val handleResult: () -> Unit = { resultHandler.returnSelectedApp(launchCookie)}
+
+        val taskId = task.taskId
+        val splitBounds = task.splitBounds
+
+        if (pssAppSelectorRecentsSplitScreen() &&
+            task.isLaunchingInSplitScreen() &&
+            !task.isForegroundTask) {
+            startSplitScreenTask(view, taskId, splitBounds!!, handleResult, activityOptions)
+        } else {
+            activityTaskManager.startActivityFromRecents(taskId, activityOptions.toBundle())
+            handleResult()
+        }
     }
 
+
     private fun createAnimation(task: RecentTask, view: View): ActivityOptions =
         if (pssAppSelectorAbruptExitFix() && task.isForegroundTask) {
             // When the selected task is in the foreground, the scale up animation doesn't work.
@@ -145,7 +172,14 @@
                 /* startedListener = */ null,
                 /* finishedListener = */ null
             )
+        } else if (task.isLaunchingInSplitScreen()) {
+            // When the selected task isn't in the foreground, but is launching in split screen,
+            // then we don't need to specify an animation, since we'll already be passing a
+            // manually built remote animation to SplitScreenController
+            ActivityOptions.makeBasic()
         } else {
+            // The default case is a selected task not in the foreground and launching fullscreen,
+            // so for this we can use the default ActivityOptions animation
             ActivityOptions.makeScaleUpAnimation(
                 view,
                 /* startX= */ 0,
@@ -155,6 +189,29 @@
             )
         }
 
+    private fun startSplitScreenTask(
+        view: View,
+        taskId: Int,
+        splitBounds: SplitBounds,
+        handleResult: () -> Unit,
+        activityOptions: ActivityOptions,
+    ) {
+        val isLeftTopTask = taskId == splitBounds.leftTopTaskId
+        val task2Id =
+            if (isLeftTopTask) splitBounds.rightBottomTaskId else splitBounds.leftTopTaskId
+        val splitPosition =
+            if (isLeftTopTask) SPLIT_POSITION_TOP_OR_LEFT else SPLIT_POSITION_BOTTOM_OR_RIGHT
+
+        val animationRunner = RemoteRecentSplitTaskTransitionRunner(taskId, task2Id,
+            view.locationOnScreen, view.context.display.naturalBounds, handleResult)
+        val remoteTransition = RemoteTransition(animationRunner,
+            view.context.iApplicationThread, "startSplitScreenTask")
+
+        splitScreen.get().startTasks(taskId, activityOptions.toBundle(), task2Id, null,
+            splitPosition, splitBounds.snapPosition, remoteTransition, null)
+    }
+
+
     override fun onTaskSizeChanged(size: Rect) {
         views?.recentsContainer?.setTaskHeightSize()
     }
@@ -163,12 +220,12 @@
         val thumbnailHeight = taskViewSizeProvider.size.height()
         val itemHeight =
             thumbnailHeight +
-                context.resources.getDimensionPixelSize(
-                    R.dimen.media_projection_app_selector_task_icon_size
-                ) +
-                context.resources.getDimensionPixelSize(
-                    R.dimen.media_projection_app_selector_task_icon_margin
-                ) * 2
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.media_projection_app_selector_task_icon_size
+                    ) +
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.media_projection_app_selector_task_icon_margin
+                    ) * 2
 
         layoutParams = layoutParams.apply { height = itemHeight }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RemoteRecentSplitTaskTransitionRunner.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RemoteRecentSplitTaskTransitionRunner.kt
new file mode 100644
index 0000000..9514c4a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RemoteRecentSplitTaskTransitionRunner.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.systemui.mediaprojection.appselector.view
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.annotation.UiThread
+import android.graphics.Rect
+import android.os.IBinder
+import android.os.RemoteException
+import android.util.Log
+import android.view.SurfaceControl
+import android.view.animation.DecelerateInterpolator
+import android.window.IRemoteTransition
+import android.window.IRemoteTransitionFinishedCallback
+import android.window.TransitionInfo
+import android.window.WindowContainerToken
+import com.android.app.viewcapture.ViewCapture
+import com.android.internal.policy.TransitionAnimation
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity.Companion.TAG
+
+class RemoteRecentSplitTaskTransitionRunner(
+    private val firstTaskId: Int,
+    private val secondTaskId: Int,
+    private val viewPosition: IntArray,
+    private val screenBounds: Rect,
+    private val handleResult: () -> Unit,
+) : IRemoteTransition.Stub() {
+    override fun startAnimation(
+        transition: IBinder?,
+        info: TransitionInfo?,
+        t: SurfaceControl.Transaction?,
+        finishedCallback: IRemoteTransitionFinishedCallback
+    ) {
+        val launchAnimation = AnimatorSet()
+        var rootCandidate =
+            info!!.changes.firstOrNull {
+                it.taskInfo?.taskId == firstTaskId || it.taskInfo?.taskId == secondTaskId
+            }
+
+        // If we could not find a proper root candidate, something went wrong.
+        check(rootCandidate != null) { "Could not find a split root candidate" }
+
+        // Recurse up the tree until parent is null, then we've found our root.
+        var parentToken: WindowContainerToken? = rootCandidate.parent
+        while (parentToken != null) {
+            rootCandidate = info.getChange(parentToken) ?: break
+            parentToken = rootCandidate.parent
+        }
+
+        // Make sure nothing weird happened, like getChange() returning null.
+        check(rootCandidate != null) { "Failed to find a root leash" }
+
+        // Ending position is the full device screen.
+        val startingScale = 0.25f
+
+        val startX = viewPosition[0]
+        val startY = viewPosition[1]
+        val endX = screenBounds.left
+        val endY = screenBounds.top
+
+        ViewCapture.MAIN_EXECUTOR.execute {
+            val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
+            with(progressUpdater) {
+                interpolator = DecelerateInterpolator(1.5f)
+                setDuration(TransitionAnimation.DEFAULT_APP_TRANSITION_DURATION.toLong())
+
+                addUpdateListener { valueAnimator ->
+                    val progress = valueAnimator.animatedFraction
+
+                    val x = startX + ((endX - startX) * progress)
+                    val y = startY + ((endY - startY) * progress)
+                    val scale = startingScale + ((1 - startingScale) * progress)
+
+                    t!!
+                        .setPosition(rootCandidate.leash, x, y)
+                        .setScale(rootCandidate.leash, scale, scale)
+                        .setAlpha(rootCandidate.leash, progress)
+                        .apply()
+                }
+
+                addListener(
+                    object : AnimatorListenerAdapter() {
+                        override fun onAnimationEnd(animation: Animator) {
+                            try {
+                                onTransitionFinished()
+                                finishedCallback.onTransitionFinished(null, null)
+                            } catch (e: RemoteException) {
+                                Log.e(TAG, "Failed to call transition finished callback", e)
+                            }
+                        }
+                    }
+                )
+            }
+
+            launchAnimation.play(progressUpdater)
+            launchAnimation.start()
+        }
+    }
+
+    override fun mergeAnimation(
+        transition: IBinder?,
+        info: TransitionInfo?,
+        t: SurfaceControl.Transaction?,
+        mergeTarget: IBinder?,
+        finishedCallback: IRemoteTransitionFinishedCallback?
+    ) {}
+
+    @Throws(RemoteException::class)
+    override fun onTransitionConsumed(transition: IBinder, aborted: Boolean) {
+        Log.w(TAG, "unexpected consumption of app selector transition: aborted=$aborted")
+    }
+
+    @UiThread
+    private fun onTransitionFinished() {
+        // After finished transition, then invoke callback to close the app selector, so that
+        // finish animation of app selector does not override the launch animation of the split
+        // tasks
+        handleResult()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index b3d848c..30f33a3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -34,7 +34,6 @@
 import androidx.core.os.postDelayed
 import androidx.core.view.isVisible
 import androidx.dynamicanimation.animation.DynamicAnimation
-import com.android.internal.jank.Cuj.CUJ_BACK_PANEL_ARROW
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.util.LatencyTracker
 import com.android.systemui.dagger.qualifiers.Main
@@ -1039,7 +1038,7 @@
     override fun dump(pw: PrintWriter) {
         pw.println("$TAG:")
         pw.println("  currentState=$currentState")
-        pw.println("  isLeftPanel=$mView.isLeftPanel")
+        pw.println("  isLeftPanel=${mView.isLeftPanel}")
     }
 
     init {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 4c86471..4e0b576 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -25,12 +25,15 @@
 import com.android.systemui.qs.FooterActionsController
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel
 import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
 import java.util.concurrent.atomic.AtomicBoolean
 import javax.inject.Inject
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 
 /** Models UI state and handles user input for the quick settings scene. */
@@ -44,20 +47,23 @@
     val notifications: NotificationsPlaceholderViewModel,
     private val footerActionsViewModelFactory: FooterActionsViewModel.Factory,
     private val footerActionsController: FooterActionsController,
+    private val sceneInteractor: SceneInteractor,
 ) {
     val destinationScenes =
-        qsSceneAdapter.isCustomizing.map { customizing ->
+        qsSceneAdapter.isCustomizing.flatMapLatest { customizing ->
             if (customizing) {
                 // TODO(b/332749288) Empty map so there are no back handlers and back can close
                 // customizer
-                emptyMap()
+                flowOf(emptyMap())
                 // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade
                 // while customizing
             } else {
-                mapOf(
-                    Back to UserActionResult(Scenes.Shade),
-                    Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
-                )
+                sceneInteractor.previousScene.map { previousScene ->
+                    mapOf(
+                        Back to UserActionResult(previousScene ?: Scenes.Shade),
+                        Swipe(SwipeDirection.Up) to UserActionResult(previousScene ?: Scenes.Shade),
+                    )
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index c929196..cff11a7 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -21,12 +21,14 @@
 import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 import com.android.systemui.Flags.sceneContainer
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.flags.FlagToken
 import com.android.systemui.flags.RefactorFlagUtils
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.KeyguardWmStateRefactor
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.shared.ComposeLockscreen
+import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent
 import com.android.systemui.media.controls.util.MediaInSceneContainerFlag
 import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
 import com.android.systemui.statusbar.phone.PredictiveBackSysUiFlag
@@ -48,7 +50,9 @@
                 MediaInSceneContainerFlag.isEnabled &&
                 MigrateClocksToBlueprint.isEnabled &&
                 NotificationsHeadsUpRefactor.isEnabled &&
-                PredictiveBackSysUiFlag.isEnabled
+                PredictiveBackSysUiFlag.isEnabled &&
+                DeviceEntryUdfpsRefactor.isEnabled &&
+                RefactorKeyguardDismissIntent.isEnabled
     // NOTE: Changes should also be made in getSecondaryFlags and @EnableSceneContainer
 
     /** The main aconfig flag. */
@@ -64,6 +68,8 @@
             MigrateClocksToBlueprint.token,
             NotificationsHeadsUpRefactor.token,
             PredictiveBackSysUiFlag.token,
+            DeviceEntryUdfpsRefactor.token,
+            RefactorKeyguardDismissIntent.token,
             // NOTE: Changes should also be made in isEnabled and @EnableSceneContainer
         )
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java
index 6224e1b..afb0280 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.screenshot;
 
+import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 
@@ -29,4 +30,9 @@
     static ScreenshotNotificationSmartActionsProvider providesScrnshtNotifSmartActionsProvider() {
         return new ScreenshotNotificationSmartActionsProvider();
     }
+
+    /** */
+    @Binds
+    ScreenshotActionsProvider.Factory bindScreenshotActionsProviderFactory(
+            DefaultScreenshotActionsProvider.Factory defaultScreenshotActionsProviderFactory);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
index 0ccb19c..3287425 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
@@ -28,7 +28,6 @@
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED
-import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED
 import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance
 import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
 import dagger.assisted.Assisted
@@ -59,7 +58,6 @@
 constructor(
     private val context: Context,
     private val viewModel: ScreenshotViewModel,
-    private val smartActionsProvider: SmartActionsProvider,
     private val uiEventLogger: UiEventLogger,
     @Assisted val request: ScreenshotData,
     @Assisted val requestId: String,
@@ -115,37 +113,6 @@
                 )
             }
         }
-
-        smartActionsProvider.requestQuickShare(request, requestId) { quickShare ->
-            if (!quickShare.actionIntent.isImmutable) {
-                viewModel.addAction(
-                    ActionButtonAppearance(
-                        quickShare.getIcon().loadDrawable(context),
-                        quickShare.title,
-                        quickShare.title
-                    )
-                ) {
-                    debugLog(LogConfig.DEBUG_ACTIONS) { "Quickshare tapped" }
-                    onDeferrableActionTapped { result ->
-                        uiEventLogger.log(
-                            SCREENSHOT_SMART_ACTION_TAPPED,
-                            0,
-                            request.packageNameString
-                        )
-                        val pendingIntentWithUri =
-                            smartActionsProvider.wrapIntent(
-                                quickShare,
-                                result.uri,
-                                result.subject,
-                                requestId
-                            )
-                        actionExecutor.sendPendingIntent(pendingIntentWithUri)
-                    }
-                }
-            } else {
-                Log.w(TAG, "Received immutable quick share pending intent; ignoring")
-            }
-        }
     }
 
     override fun onScrollChipReady(onClick: Runnable) {
@@ -167,21 +134,6 @@
         }
         this.result = result
         pendingAction?.invoke(result)
-        smartActionsProvider.requestSmartActions(request, requestId, result) { smartActions ->
-            smartActions.forEach {
-                smartActions.forEach { action ->
-                    viewModel.addAction(
-                        ActionButtonAppearance(
-                            action.getIcon().loadDrawable(context),
-                            action.title,
-                            action.title,
-                        )
-                    ) {
-                        actionExecutor.sendPendingIntent(action.actionIntent)
-                    }
-                }
-            }
-        }
     }
 
     private fun onDeferrableActionTapped(onResult: (ScreenshotSavedResult) -> Unit) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 13dd229..0e48bef 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -176,11 +176,12 @@
 
     // These strings are used for communicating the action invoked to
     // ScreenshotNotificationSmartActionsProvider.
-    static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
-    static final String EXTRA_ID = "android:screenshot_id";
-    static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
-    static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
-    static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";
+    public static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
+    public static final String EXTRA_ID = "android:screenshot_id";
+    public static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
+    public static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
+    public static final String EXTRA_ACTION_INTENT_FILLIN =
+            "android:screenshot_action_intent_fillin";
 
 
     // From WizardManagerHelper.java
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
index 3eafbfb..23f05e0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java
@@ -44,7 +44,7 @@
     public static final String DEFAULT_ACTION_TYPE = "Smart Action";
 
     /* Define phases of screenshot execution. */
-    protected enum ScreenshotOp {
+    public enum ScreenshotOp {
         OP_UNKNOWN,
         RETRIEVE_SMART_ACTIONS,
         REQUEST_SMART_ACTIONS,
@@ -52,7 +52,7 @@
     }
 
     /* Enum to report success or failure for screenshot execution phases. */
-    protected enum ScreenshotOpStatus {
+    public enum ScreenshotOpStatus {
         OP_STATUS_UNKNOWN,
         SUCCESS,
         ERROR,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt
deleted file mode 100644
index a895b30..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * 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.systemui.screenshot
-
-import android.app.Notification
-import android.app.PendingIntent
-import android.content.ClipData
-import android.content.ClipDescription
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.graphics.Bitmap
-import android.net.Uri
-import android.os.Bundle
-import android.os.Process
-import android.os.SystemClock
-import android.os.UserHandle
-import android.provider.DeviceConfig
-import android.util.Log
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
-import com.android.systemui.log.DebugLogger.debugLog
-import com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS
-import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.QUICK_SHARE_ACTION
-import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.REGULAR_SMART_ACTIONS
-import java.util.concurrent.CompletableFuture
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeoutException
-import javax.inject.Inject
-import kotlin.random.Random
-
-/**
- * Handle requesting smart/quickshare actions from the provider and executing an action when the
- * action futures complete.
- */
-class SmartActionsProvider
-@Inject
-constructor(
-    private val context: Context,
-    private val smartActions: ScreenshotNotificationSmartActionsProvider,
-) {
-    /**
-     * Requests quick share action for a given screenshot.
-     *
-     * @param data the ScreenshotData request
-     * @param id the request id for the screenshot
-     * @param onAction callback to run when quick share action is returned
-     */
-    fun requestQuickShare(
-        data: ScreenshotData,
-        id: String,
-        onAction: (Notification.Action) -> Unit
-    ) {
-        val bitmap = data.bitmap ?: return
-        val component = data.topComponent ?: ComponentName("", "")
-        requestQuickShareAction(id, bitmap, component, data.getUserOrDefault()) { quickShare ->
-            onAction(quickShare)
-        }
-    }
-
-    /**
-     * Requests smart actions for a given screenshot.
-     *
-     * @param data the ScreenshotData request
-     * @param id the request id for the screenshot
-     * @param result the data for the saved image
-     * @param onActions callback to run when actions are returned
-     */
-    fun requestSmartActions(
-        data: ScreenshotData,
-        id: String,
-        result: ScreenshotSavedResult,
-        onActions: (List<Notification.Action>) -> Unit
-    ) {
-        val bitmap = data.bitmap ?: return
-        val component = data.topComponent ?: ComponentName("", "")
-        requestSmartActions(
-            id,
-            bitmap,
-            component,
-            data.getUserOrDefault(),
-            result.uri,
-            REGULAR_SMART_ACTIONS
-        ) { actions ->
-            onActions(actions)
-        }
-    }
-
-    /**
-     * Wraps the given quick share action in a broadcast intent.
-     *
-     * @param quickShare the quick share action to wrap
-     * @param uri the URI of the saved screenshot
-     * @param subject the subject/title for the screenshot
-     * @param id the request ID of the screenshot
-     * @return the pending intent with correct URI
-     */
-    fun wrapIntent(
-        quickShare: Notification.Action,
-        uri: Uri,
-        subject: String,
-        id: String
-    ): PendingIntent {
-        val wrappedIntent: Intent =
-            Intent(context, SmartActionsReceiver::class.java)
-                .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent)
-                .putExtra(
-                    ScreenshotController.EXTRA_ACTION_INTENT_FILLIN,
-                    createFillInIntent(uri, subject)
-                )
-                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-        val extras: Bundle = quickShare.extras
-        val actionType =
-            extras.getString(
-                ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
-                ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE
-            )
-        // We only query for quick share actions when smart actions are enabled, so we can assert
-        // that it's true here.
-        wrappedIntent
-            .putExtra(ScreenshotController.EXTRA_ACTION_TYPE, actionType)
-            .putExtra(ScreenshotController.EXTRA_ID, id)
-            .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, true)
-        return PendingIntent.getBroadcast(
-            context,
-            Random.nextInt(),
-            wrappedIntent,
-            PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
-        )
-    }
-
-    private fun createFillInIntent(uri: Uri, subject: String): Intent {
-        val fillIn = Intent()
-        fillIn.setType("image/png")
-        fillIn.putExtra(Intent.EXTRA_STREAM, uri)
-        fillIn.putExtra(Intent.EXTRA_SUBJECT, subject)
-        // Include URI in ClipData also, so that grantPermission picks it up.
-        // We don't use setData here because some apps interpret this as "to:".
-        val clipData =
-            ClipData(ClipDescription("content", arrayOf("image/png")), ClipData.Item(uri))
-        fillIn.clipData = clipData
-        fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
-        return fillIn
-    }
-
-    private fun requestQuickShareAction(
-        id: String,
-        image: Bitmap,
-        component: ComponentName,
-        user: UserHandle,
-        timeoutMs: Long = 500,
-        onAction: (Notification.Action) -> Unit
-    ) {
-        requestSmartActions(id, image, component, user, null, QUICK_SHARE_ACTION, timeoutMs) {
-            it.firstOrNull()?.let { action -> onAction(action) }
-        }
-    }
-
-    private fun requestSmartActions(
-        id: String,
-        image: Bitmap,
-        component: ComponentName,
-        user: UserHandle,
-        uri: Uri?,
-        actionType: ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType,
-        timeoutMs: Long = 500,
-        onActions: (List<Notification.Action>) -> Unit
-    ) {
-        val enabled = isSmartActionsEnabled(user)
-        debugLog(DEBUG_ACTIONS) {
-            ("getSmartActionsFuture id=$id, uri=$uri, provider=$smartActions, " +
-                "actionType=$actionType, smartActionsEnabled=$enabled, userHandle=$user")
-        }
-        if (!enabled) {
-            debugLog(DEBUG_ACTIONS) { "Screenshot Intelligence not enabled, returning empty list" }
-            onActions(listOf())
-            return
-        }
-        if (image.config != Bitmap.Config.HARDWARE) {
-            debugLog(DEBUG_ACTIONS) {
-                "Bitmap expected: Hardware, Bitmap found: ${image.config}. Returning empty list."
-            }
-            onActions(listOf())
-            return
-        }
-        val smartActionsFuture: CompletableFuture<List<Notification.Action>>
-        val startTimeMs = SystemClock.uptimeMillis()
-        try {
-            smartActionsFuture =
-                smartActions.getActions(id, uri, image, component, actionType, user)
-        } catch (e: Throwable) {
-            val waitTimeMs = SystemClock.uptimeMillis() - startTimeMs
-            debugLog(DEBUG_ACTIONS, error = e) {
-                "Failed to get future for screenshot notification smart actions."
-            }
-            notifyScreenshotOp(
-                id,
-                ScreenshotNotificationSmartActionsProvider.ScreenshotOp.REQUEST_SMART_ACTIONS,
-                ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR,
-                waitTimeMs
-            )
-            onActions(listOf())
-            return
-        }
-        try {
-            val actions = smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS)
-            val waitTimeMs = SystemClock.uptimeMillis() - startTimeMs
-            debugLog(DEBUG_ACTIONS) {
-                ("Got ${actions.size} smart actions. Wait time: $waitTimeMs ms, " +
-                    "actionType=$actionType")
-            }
-            notifyScreenshotOp(
-                id,
-                ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS,
-                ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.SUCCESS,
-                waitTimeMs
-            )
-            onActions(actions)
-        } catch (e: Throwable) {
-            val waitTimeMs = SystemClock.uptimeMillis() - startTimeMs
-            debugLog(DEBUG_ACTIONS, error = e) {
-                "Error getting smart actions. Wait time: $waitTimeMs ms, actionType=$actionType"
-            }
-            val status =
-                if (e is TimeoutException) {
-                    ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.TIMEOUT
-                } else {
-                    ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR
-                }
-            notifyScreenshotOp(
-                id,
-                ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS,
-                status,
-                waitTimeMs
-            )
-            onActions(listOf())
-        }
-    }
-
-    private fun notifyScreenshotOp(
-        screenshotId: String,
-        op: ScreenshotNotificationSmartActionsProvider.ScreenshotOp,
-        status: ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus,
-        durationMs: Long
-    ) {
-        debugLog(DEBUG_ACTIONS) {
-            "$smartActions notifyOp: $op id=$screenshotId, status=$status, durationMs=$durationMs"
-        }
-        try {
-            smartActions.notifyOp(screenshotId, op, status, durationMs)
-        } catch (e: Throwable) {
-            Log.e(TAG, "Error in notifyScreenshotOp: ", e)
-        }
-    }
-
-    private fun isSmartActionsEnabled(user: UserHandle): Boolean {
-        // Smart actions don't yet work for cross-user saves.
-        val savingToOtherUser = user !== Process.myUserHandle()
-        val actionsEnabled =
-            DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS,
-                true
-            )
-        return !savingToOtherUser && actionsEnabled
-    }
-
-    companion object {
-        private const val TAG = "SmartActionsProvider"
-        private const val SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)"
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
index 6ff0fda..ab23e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -22,11 +22,9 @@
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.screenshot.DefaultScreenshotActionsProvider;
 import com.android.systemui.screenshot.ImageCapture;
 import com.android.systemui.screenshot.ImageCaptureImpl;
 import com.android.systemui.screenshot.LegacyScreenshotViewProxy;
-import com.android.systemui.screenshot.ScreenshotActionsProvider;
 import com.android.systemui.screenshot.ScreenshotPolicy;
 import com.android.systemui.screenshot.ScreenshotPolicyImpl;
 import com.android.systemui.screenshot.ScreenshotShelfViewProxy;
@@ -90,10 +88,6 @@
     abstract ScreenshotSoundController bindScreenshotSoundController(
             ScreenshotSoundControllerImpl screenshotSoundProviderImpl);
 
-    @Binds
-    abstract ScreenshotActionsProvider.Factory bindScreenshotActionsProviderFactory(
-            DefaultScreenshotActionsProvider.Factory defaultScreenshotActionsProviderFactory);
-
     @Provides
     @SysUISingleton
     static ScreenshotViewModel providesScreenshotViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt
index 4a88180..0fb5366 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt
@@ -22,7 +22,28 @@
 fun interface CapturePolicy {
     /**
      * Test the policy against the current display task state. If the policy applies, Returns a
-     * non-null [CaptureParameters] describing how the screenshot request should be augmented.
+     * [PolicyResult.Matched] containing [CaptureParameters] used to alter the request.
      */
-    suspend fun apply(content: DisplayContentModel): CaptureParameters?
+    suspend fun check(content: DisplayContentModel): PolicyResult
+
+    /** The result of a screen capture policy check. */
+    sealed interface PolicyResult {
+        /** The policy rules matched the given display content and will be applied. */
+        data class Matched(
+            /** The name of the policy rule which matched. */
+            val policy: String,
+            /** Why the policy matched. */
+            val reason: String,
+            /** Details on how to modify the screen capture request. */
+            val parameters: CaptureParameters,
+        ) : PolicyResult
+
+        /** The policy rules do not match the given display content and do not apply. */
+        data class NotMatched(
+            /** The name of the policy rule which matched. */
+            val policy: String,
+            /** Why the policy did not match. */
+            val reason: String
+        ) : PolicyResult
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt
index 6ca2e9d6..0ef5207 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt
@@ -21,10 +21,10 @@
 /** What to capture */
 sealed interface CaptureType {
     /** Capture the entire screen contents. */
-    class FullScreen(val displayId: Int) : CaptureType
+    data class FullScreen(val displayId: Int) : CaptureType
 
     /** Capture the contents of the task only. */
-    class IsolatedTask(
+    data class IsolatedTask(
         val taskId: Int,
         val taskBounds: Rect?,
     ) : CaptureType
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
index 2c0a0db..80aa0ef 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt
@@ -16,9 +16,12 @@
 
 package com.android.systemui.screenshot.policy
 
+import android.app.ActivityTaskManager.RootTaskInfo
+import android.app.WindowConfiguration
 import android.content.ComponentName
 import android.graphics.Bitmap
 import android.graphics.Rect
+import android.os.Process.myUserHandle
 import android.os.UserHandle
 import android.util.Log
 import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
@@ -27,7 +30,10 @@
 import com.android.systemui.screenshot.ImageCapture
 import com.android.systemui.screenshot.ScreenshotData
 import com.android.systemui.screenshot.ScreenshotRequestProcessor
+import com.android.systemui.screenshot.data.model.DisplayContentModel
 import com.android.systemui.screenshot.data.repository.DisplayContentRepository
+import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.Matched
+import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched
 import com.android.systemui.screenshot.policy.CaptureType.FullScreen
 import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask
 import kotlinx.coroutines.CoroutineDispatcher
@@ -39,8 +45,14 @@
 class PolicyRequestProcessor(
     @Background private val background: CoroutineDispatcher,
     private val capture: ImageCapture,
+    /** Provides information about the tasks on a given display */
     private val displayTasks: DisplayContentRepository,
+    /** The list of policies to apply, in order of priority */
     private val policies: List<CapturePolicy>,
+    /** The owner to assign for screenshot when a focused task isn't visible */
+    private val defaultOwner: UserHandle = myUserHandle(),
+    /** The assigned component when no application has focus, or not visible */
+    private val defaultComponent: ComponentName,
 ) : ScreenshotRequestProcessor {
     override suspend fun process(original: ScreenshotData): ScreenshotData {
         if (original.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
@@ -48,29 +60,26 @@
             Log.i(TAG, "Screenshot bitmap provided. No modifications applied.")
             return original
         }
-
-        val tasks = displayTasks.getDisplayContent(original.displayId)
+        val displayContent = displayTasks.getDisplayContent(original.displayId)
 
         // If policies yield explicit modifications, apply them and return the result
         Log.i(TAG, "Applying policy checks....")
-        policies
-            .firstNotNullOfOrNull { policy -> policy.apply(tasks) }
-            ?.let {
-                Log.i(TAG, "Modifying screenshot: $it")
-                return apply(it, original)
+        policies.map { policy ->
+            when (val result = policy.check(displayContent)) {
+                is Matched -> {
+                    Log.i(TAG, "$result")
+                    return modify(original, result.parameters)
+                }
+                is NotMatched -> Log.i(TAG, "$result")
             }
+        }
 
         // Otherwise capture normally, filling in additional information as needed.
-        return replaceWithScreenshot(
-            original = original,
-            componentName = original.topComponent ?: tasks.rootTasks.firstOrNull()?.topActivity,
-            owner = original.userHandle,
-            displayId = original.displayId
-        )
+        return captureScreenshot(original, displayContent)
     }
 
     /** Produce a new [ScreenshotData] using [CaptureParameters] */
-    suspend fun apply(updates: CaptureParameters, original: ScreenshotData): ScreenshotData {
+    suspend fun modify(original: ScreenshotData, updates: CaptureParameters): ScreenshotData {
         // Update and apply bitmap capture depending on the parameters.
         val updated =
             when (val type = updates.type) {
@@ -93,6 +102,26 @@
         return updated
     }
 
+    private suspend fun captureScreenshot(
+        original: ScreenshotData,
+        displayContent: DisplayContentModel,
+    ): ScreenshotData {
+        // The first root task on the display, excluding Picture-in-Picture
+        val topMainRootTask =
+            if (!displayContent.systemUiState.shadeExpanded) {
+                displayContent.rootTasks.firstOrNull(::nonPipVisibleTask)
+            } else {
+                null // Otherwise attributed to SystemUI / current user
+            }
+
+        return replaceWithScreenshot(
+            original = original,
+            componentName = topMainRootTask?.topActivity ?: defaultComponent,
+            owner = topMainRootTask?.userId?.let { UserHandle.of(it) } ?: defaultOwner,
+            displayId = original.displayId
+        )
+    }
+
     suspend fun replaceWithTaskSnapshot(
         original: ScreenshotData,
         componentName: ComponentName?,
@@ -100,6 +129,7 @@
         taskId: Int,
         taskBounds: Rect?,
     ): ScreenshotData {
+        Log.i(TAG, "Capturing task snapshot: $componentName / $owner")
         val taskSnapshot = capture.captureTask(taskId)
         return original.copy(
             type = TAKE_SCREENSHOT_PROVIDED_IMAGE,
@@ -117,6 +147,7 @@
         owner: UserHandle?,
         displayId: Int,
     ): ScreenshotData {
+        Log.i(TAG, "Capturing screenshot: $componentName / $owner")
         val screenshot = captureDisplay(displayId)
         return original.copy(
             type = TAKE_SCREENSHOT_FULLSCREEN,
@@ -127,6 +158,16 @@
         )
     }
 
+    /** Filter for the task used to attribute a full screen capture to an owner */
+    private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
+        return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED &&
+            info.isVisible &&
+            info.isRunning &&
+            info.numActivities > 0 &&
+            info.topActivity != null &&
+            info.childTaskIds.isNotEmpty()
+    }
+
     /** TODO: Move to ImageCapture (existing function is non-suspending) */
     private suspend fun captureDisplay(displayId: Int): Bitmap? {
         return withContext(background) { capture.captureDisplay(displayId) }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt
index 221e647..6373a58 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt
@@ -20,10 +20,13 @@
 import com.android.systemui.screenshot.data.model.DisplayContentModel
 import com.android.systemui.screenshot.data.model.ProfileType
 import com.android.systemui.screenshot.data.repository.ProfileTypeRepository
+import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult
+import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.Matched
+import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched
 import com.android.systemui.screenshot.policy.CaptureType.FullScreen
 import javax.inject.Inject
-import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.firstOrNull
+
+private const val POLICY_NAME = "PrivateProfile"
 
 /**
  * Condition: When any visible task belongs to a private user.
@@ -35,7 +38,12 @@
 constructor(
     private val profileTypes: ProfileTypeRepository,
 ) : CapturePolicy {
-    override suspend fun apply(content: DisplayContentModel): CaptureParameters? {
+    override suspend fun check(content: DisplayContentModel): PolicyResult {
+        // The systemUI notification shade isn't a private profile app, skip.
+        if (content.systemUiState.shadeExpanded) {
+            return NotMatched(policy = POLICY_NAME, reason = "Notification shade is expanded")
+        }
+
         // Find the first visible rootTaskInfo with a child task owned by a private user
         val (rootTask, childTask) =
             content.rootTasks
@@ -48,13 +56,20 @@
                         }
                         ?.let { root to it }
                 }
-                ?: return null
+                ?: return NotMatched(
+                    policy = POLICY_NAME,
+                    reason = "No private profile tasks are visible"
+                )
 
         // If matched, return parameters needed to modify the request.
-        return CaptureParameters(
-            type = FullScreen(content.displayId),
-            component = childTask.componentName ?: rootTask.topActivity,
-            owner = UserHandle.of(childTask.userId),
+        return Matched(
+            policy = POLICY_NAME,
+            reason = "At least one private profile task is visible",
+            CaptureParameters(
+                type = FullScreen(content.displayId),
+                component = childTask.componentName ?: rootTask.topActivity,
+                owner = UserHandle.of(childTask.userId),
+            )
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt
index d2f4d9e..3789371 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt
@@ -18,12 +18,10 @@
 
 import android.app.ActivityTaskManager.RootTaskInfo
 import com.android.systemui.screenshot.data.model.ChildTaskModel
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.asFlow
-import kotlinx.coroutines.flow.map
 
-internal fun RootTaskInfo.childTasksTopDown(): Flow<ChildTaskModel> {
-    return ((numActivities - 1) downTo 0).asFlow().map { index ->
+/** The child tasks of A RootTaskInfo as [ChildTaskModel] in top-down (z-index ascending) order. */
+internal fun RootTaskInfo.childTasksTopDown(): Sequence<ChildTaskModel> {
+    return ((childTaskIds.size - 1) downTo 0).asSequence().map { index ->
         ChildTaskModel(
             childTaskIds[index],
             childTaskNames[index],
@@ -32,16 +30,3 @@
         )
     }
 }
-
-internal suspend fun RootTaskInfo.firstChildTaskOrNull(
-    filter: suspend (Int) -> Boolean
-): Pair<RootTaskInfo, Int>? {
-    // Child tasks are provided in bottom-up order
-    // Filtering is done top-down, so iterate backwards here.
-    for (index in numActivities - 1 downTo 0) {
-        if (filter(index)) {
-            return (this to index)
-        }
-    }
-    return null
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
index 63d1508..a6b01e7 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt
@@ -16,8 +16,13 @@
 
 package com.android.systemui.screenshot.policy
 
+import android.content.ComponentName
+import android.content.Context
+import android.os.Process
 import com.android.systemui.Flags.screenshotPrivateProfile
+import com.android.systemui.SystemUIService
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.screenshot.ImageCapture
 import com.android.systemui.screenshot.RequestProcessor
@@ -60,6 +65,7 @@
         @Provides
         @SysUISingleton
         fun bindScreenshotRequestProcessor(
+            @Application context: Context,
             @Background background: CoroutineDispatcher,
             imageCapture: ImageCapture,
             policyProvider: Provider<ScreenshotPolicy>,
@@ -68,10 +74,13 @@
         ): ScreenshotRequestProcessor {
             return if (screenshotPrivateProfile()) {
                 PolicyRequestProcessor(
-                    background,
-                    imageCapture,
-                    displayContentRepoProvider.get(),
-                    policyListProvider.get()
+                    background = background,
+                    capture = imageCapture,
+                    displayTasks = displayContentRepoProvider.get(),
+                    policies = policyListProvider.get(),
+                    defaultOwner = Process.myUserHandle(),
+                    defaultComponent =
+                        ComponentName(context.packageName, SystemUIService::class.java.toString())
                 )
             } else {
                 RequestProcessor(imageCapture, policyProvider.get())
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt
index d6b5d6d..689cc11 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt
@@ -21,10 +21,14 @@
 import com.android.systemui.screenshot.data.model.DisplayContentModel
 import com.android.systemui.screenshot.data.model.ProfileType
 import com.android.systemui.screenshot.data.repository.ProfileTypeRepository
+import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult
+import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched
 import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask
 import javax.inject.Inject
 import kotlinx.coroutines.flow.first
 
+private const val POLICY_NAME = "WorkProfile"
+
 /**
  * Condition: When the top visible task (excluding PIP mode) belongs to a work user.
  *
@@ -35,7 +39,12 @@
 constructor(
     private val profileTypes: ProfileTypeRepository,
 ) : CapturePolicy {
-    override suspend fun apply(content: DisplayContentModel): CaptureParameters? {
+    override suspend fun check(content: DisplayContentModel): PolicyResult {
+        // The systemUI notification shade isn't a work app, skip.
+        if (content.systemUiState.shadeExpanded) {
+            return NotMatched(policy = POLICY_NAME, reason = "Notification shade is expanded")
+        }
+
         // Find the first non PiP rootTask with a top child task owned by a work user
         val (rootTask, childTask) =
             content.rootTasks
@@ -44,13 +53,20 @@
                 .firstOrNull { (_, child) ->
                     profileTypes.getProfileType(child.userId) == ProfileType.WORK
                 }
-                ?: return null
+                ?: return NotMatched(
+                    policy = POLICY_NAME,
+                    reason = "The top-most non-PINNED task does not belong to a work profile user"
+                )
 
         // If matched, return parameters needed to modify the request.
-        return CaptureParameters(
-            type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds),
-            component = childTask.componentName ?: rootTask.topActivity,
-            owner = UserHandle.of(childTask.userId),
+        return PolicyResult.Matched(
+            policy = POLICY_NAME,
+            reason = "The top-most non-PINNED task ($childTask) belongs to a work profile user",
+            CaptureParameters(
+                type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds),
+                component = childTask.componentName ?: rootTask.topActivity,
+                owner = UserHandle.of(childTask.userId),
+            )
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index bb6ee24..f8193a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -57,6 +57,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
+import com.android.systemui.Flags;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.NotificationContentDescription;
 import com.android.systemui.statusbar.notification.NotificationDozeHelper;
@@ -208,6 +209,10 @@
         initializeDecorColor();
         reloadDimens();
         maybeUpdateIconScaleDimens();
+
+        if (Flags.statusBarMonochromeIconsFix()) {
+            setCropToPadding(true);
+        }
     }
 
     /** Should always be preceded by {@link #reloadDimens()} */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 0486ef5..13e36d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -350,7 +350,8 @@
      *
      * When the shade is expanding, the position is controlled by... the shade.
      */
-    val bounds: StateFlow<NotificationContainerBounds> =
+    val bounds: StateFlow<NotificationContainerBounds> by lazy {
+        SceneContainerFlag.assertInLegacyMode()
         combine(
                 isOnLockscreenWithoutShade,
                 keyguardInteractor.notificationContainerBounds,
@@ -380,6 +381,7 @@
                 initialValue = NotificationContainerBounds(),
             )
             .dumpValue("bounds")
+    }
 
     /**
      * Ensure view is visible when the shade/qs are expanded. Also, as QS is expanding, fade out
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5f26702..077f330 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -67,12 +67,12 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardWmStateRefactor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
+import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent;
 import com.android.systemui.keyguard.shared.model.DismissAction;
 import com.android.systemui.keyguard.shared.model.KeyguardDone;
 import com.android.systemui.keyguard.shared.model.KeyguardState;
@@ -381,7 +381,6 @@
             Lazy<ShadeController> shadeController,
             LatencyTracker latencyTracker,
             KeyguardSecurityModel keyguardSecurityModel,
-            FeatureFlags featureFlags,
             PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,
             PrimaryBouncerInteractor primaryBouncerInteractor,
             BouncerView primaryBouncerView,
@@ -413,7 +412,6 @@
         mShadeController = shadeController;
         mLatencyTracker = latencyTracker;
         mKeyguardSecurityModel = keyguardSecurityModel;
-        mFlags = featureFlags;
         mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor;
         mPrimaryBouncerInteractor = primaryBouncerInteractor;
         mPrimaryBouncerView = primaryBouncerView;
@@ -805,7 +803,7 @@
 
     public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
             boolean afterKeyguardGone, String message) {
-        if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (RefactorKeyguardDismissIntent.isEnabled()) {
             if (r == null) {
                 return;
             }
@@ -857,7 +855,7 @@
                     return;
                 }
 
-                if (!mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+                if (!RefactorKeyguardDismissIntent.isEnabled()) {
                     mAfterKeyguardGoneAction = r;
                     mKeyguardGoneCancelAction = cancelAction;
                     mDismissActionWillAnimateOnKeyguard = r != null
@@ -925,7 +923,7 @@
      * Adds a {@param runnable} to be executed after Keyguard is gone.
      */
     public void addAfterKeyguardGoneRunnable(Runnable runnable) {
-        if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (RefactorKeyguardDismissIntent.isEnabled()) {
             if (runnable != null) {
                 mKeyguardDismissActionInteractor.get().runAfterKeyguardGone(runnable);
             }
@@ -1118,7 +1116,7 @@
             // We update the state (which will show the keyguard) only if an animation will run on
             // the keyguard. If there is no animation, we wait before updating the state so that we
             // go directly from bouncer to launcher/app.
-            if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+            if (RefactorKeyguardDismissIntent.isEnabled()) {
                 if (mKeyguardDismissActionInteractor.get().runDismissAnimationOnKeyguard()) {
                     updateStates();
                 }
@@ -1245,7 +1243,7 @@
     }
 
     private void executeAfterKeyguardGoneAction() {
-        if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+        if (RefactorKeyguardDismissIntent.isEnabled()) {
             return;
         }
         if (mAfterKeyguardGoneAction != null) {
@@ -1634,7 +1632,7 @@
         pw.println("  bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing());
         pw.println("  Registered KeyguardViewManagerCallbacks:");
         pw.println(" refactorKeyguardDismissIntent enabled:"
-                + mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT));
+                + RefactorKeyguardDismissIntent.isEnabled());
         for (KeyguardViewManagerCallback callback : mCallbacks) {
             pw.println("      " + callback);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
index 8f18aa8..8ce3b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
@@ -41,12 +41,14 @@
 interface AncSliceRepository {
 
     /**
-     * ANC slice with a given width. Emits null when there is no ANC slice available. This can mean
-     * that:
+     * ANC slice with a given width. [isCollapsed] slice shows a single button, and expanded shows a
+     * row buttons.
+     *
+     * Emits null when there is no ANC slice available. This can mean that:
      * - there is no supported device connected;
      * - there is no slice provider for the uri;
      */
-    fun ancSlice(width: Int): Flow<Slice?>
+    fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?>
 }
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -60,9 +62,14 @@
 
     private val localMediaRepository = mediaRepositoryFactory.create(null)
 
-    override fun ancSlice(width: Int): Flow<Slice?> {
+    override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
         return localMediaRepository.currentConnectedDevice
-            .map { (it as? BluetoothMediaDevice)?.cachedDevice?.device?.getExtraControlUri(width) }
+            .map {
+                (it as? BluetoothMediaDevice)
+                    ?.cachedDevice
+                    ?.device
+                    ?.getExtraControlUri(width, isCollapsed, hideLabel)
+            }
             .distinctUntilChanged()
             .flatMapLatest { sliceUri ->
                 sliceUri ?: return@flatMapLatest flowOf(null)
@@ -71,7 +78,11 @@
             .flowOn(backgroundCoroutineContext)
     }
 
-    private fun BluetoothDevice.getExtraControlUri(width: Int): Uri? {
+    private fun BluetoothDevice.getExtraControlUri(
+        width: Int,
+        isCollapsed: Boolean,
+        hideLabel: Boolean
+    ): Uri? {
         val uri: String? = BluetoothUtils.getControlUriMetaData(this)
         uri ?: return null
 
@@ -81,7 +92,8 @@
             Uri.parse(
                 "$uri$width" +
                     "&version=${SliceParameters.VERSION}" +
-                    "&is_collapsed=${SliceParameters.IS_COLLAPSED}"
+                    "&is_collapsed=$isCollapsed" +
+                    "&hide_label=$hideLabel"
             )
         }
     }
@@ -98,11 +110,5 @@
          * 2) new slice
          */
         const val VERSION = 2
-
-        /**
-         * Collapsed slice shows a single button, and expanded shows a row buttons. Supported since
-         * [VERSION]==2.
-         */
-        const val IS_COLLAPSED = false
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt
index 89b9274..dc4be26 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.volume.panel.component.anc.domain
 
 import com.android.systemui.volume.panel.component.anc.domain.interactor.AncSliceInteractor
+import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
 import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
 import javax.inject.Inject
@@ -31,5 +32,6 @@
     private val ancSliceInteractor: AncSliceInteractor,
 ) : ComponentAvailabilityCriteria {
 
-    override fun isAvailable(): Flow<Boolean> = ancSliceInteractor.ancSlice.map { it != null }
+    override fun isAvailable(): Flow<Boolean> =
+        ancSliceInteractor.ancSlices.map { it is AncSlices.Ready }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
index 91af622..cefa269 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
@@ -20,16 +20,19 @@
 import android.app.slice.SliceItem.FORMAT_SLICE
 import androidx.slice.Slice
 import com.android.systemui.volume.panel.component.anc.data.repository.AncSliceRepository
+import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharedFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
 
 /** Provides a valid slice from [AncSliceRepository]. */
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -41,25 +44,35 @@
     scope: CoroutineScope,
 ) {
 
-    // Start with a positive width to check is the Slice is available.
-    private val width = MutableStateFlow(1)
+    // Any positive width to check if the Slice is available.
+    private val buttonSliceWidth = MutableStateFlow(1)
+    private val popupSliceWidth = MutableStateFlow(1)
 
-    /** Provides a valid ANC slice. */
-    val ancSlice: SharedFlow<Slice?> =
-        width
-            .flatMapLatest { width -> ancSliceRepository.ancSlice(width) }
-            .map { slice ->
-                if (slice?.isValidSlice() == true) {
-                    slice
+    val ancSlices: StateFlow<AncSlices> =
+        combine(
+                buttonSliceWidth.flatMapLatest {
+                    ancSlice(width = it, isCollapsed = true, hideLabel = true)
+                },
+                popupSliceWidth.flatMapLatest {
+                    ancSlice(width = it, isCollapsed = false, hideLabel = false)
+                }
+            ) { buttonSlice, popupSlice ->
+                if (buttonSlice != null && popupSlice != null) {
+                    AncSlices.Ready(buttonSlice = buttonSlice, popupSlice = popupSlice)
                 } else {
-                    null
+                    AncSlices.Unavailable
                 }
             }
-            .shareIn(scope, SharingStarted.Eagerly, replay = 1)
+            .stateIn(scope, SharingStarted.Eagerly, AncSlices.Unavailable)
 
-    /** Updates the width of the [ancSlice] */
-    fun changeWidth(newWidth: Int) {
-        width.value = newWidth
+    /**
+     * Provides a valid [isCollapsed] ANC slice for a given [width]. Use [hideLabel] == true to
+     * remove the labels from the [Slice].
+     */
+    private fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
+        return ancSliceRepository
+            .ancSlice(width = width, isCollapsed = isCollapsed, hideLabel = hideLabel)
+            .filter { it?.isValidSlice() != false }
     }
 
     private fun Slice.isValidSlice(): Boolean {
@@ -73,4 +86,20 @@
         }
         return false
     }
+
+    /**
+     * Call this to update [AncSlices.Ready.popupSlice] width in a reaction to container size
+     * change.
+     */
+    fun onPopupSliceWidthChanged(width: Int) {
+        popupSliceWidth.tryEmit(width)
+    }
+
+    /**
+     * Call this to update [AncSlices.Ready.buttonSlice] width in a reaction to container size
+     * change.
+     */
+    fun onButtonSliceWidthChanged(width: Int) {
+        buttonSliceWidth.tryEmit(width)
+    }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/model/AncSlices.kt
similarity index 63%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
copy to packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/model/AncSlices.kt
index f6140f5..3cd4e67 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/model/AncSlices.kt
@@ -14,9 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.credentialmanager.common
+package com.android.systemui.volume.panel.component.anc.domain.model
 
-enum class FlowType {
-    GET,
-    CREATE
-}
\ No newline at end of file
+import androidx.slice.Slice
+
+/** Modes current ANC slices state */
+sealed interface AncSlices {
+
+    data class Ready(
+        val popupSlice: Slice,
+        val buttonSlice: Slice,
+    ) : AncSlices
+
+    /** Couldn't one or both slices. */
+    data object Unavailable : AncSlices
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt
index eb96f6c..bee79bb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt
@@ -16,52 +16,56 @@
 
 package com.android.systemui.volume.panel.component.anc.ui.viewmodel
 
-import android.content.Context
 import androidx.slice.Slice
-import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.res.R
+import com.android.systemui.volume.panel.component.anc.domain.AncAvailabilityCriteria
 import com.android.systemui.volume.panel.component.anc.domain.interactor.AncSliceInteractor
-import com.android.systemui.volume.panel.component.button.ui.viewmodel.ButtonViewModel
+import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterIsInstance
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
 /** Volume Panel ANC component view model. */
+@OptIn(ExperimentalCoroutinesApi::class)
 @VolumePanelScope
 class AncViewModel
 @Inject
 constructor(
-    @Application private val context: Context,
     @VolumePanelScope private val coroutineScope: CoroutineScope,
     private val interactor: AncSliceInteractor,
+    private val availabilityCriteria: AncAvailabilityCriteria,
 ) {
 
-    /** ANC [Slice]. Null when there is no slice available for ANC. */
-    val slice: StateFlow<Slice?> =
-        interactor.ancSlice.stateIn(coroutineScope, SharingStarted.Eagerly, null)
+    val isAvailable: Flow<Boolean>
+        get() = availabilityCriteria.isAvailable()
 
-    /**
-     * ButtonViewModel to be shown in the VolumePanel. Null when there is no ANC Slice available.
-     */
-    val button: StateFlow<ButtonViewModel?> =
-        interactor.ancSlice
-            .map { slice ->
-                slice?.let {
-                    ButtonViewModel(
-                        Icon.Resource(R.drawable.ic_noise_aware, null),
-                        context.getString(R.string.volume_panel_noise_control_title)
-                    )
-                }
-            }
+    /** ANC [Slice]. Null when there is no slice available for ANC. */
+    val popupSlice: StateFlow<Slice?> =
+        interactor.ancSlices
+            .filterIsInstance<AncSlices.Ready>()
+            .map { it.popupSlice }
             .stateIn(coroutineScope, SharingStarted.Eagerly, null)
 
-    /** Call this to update [slice] width in a reaction to container size change. */
-    fun changeSliceWidth(width: Int) {
-        interactor.changeWidth(width)
+    /** Button [Slice] to be shown in the VolumePanel. Null when there is no ANC Slice available. */
+    val buttonSlice: StateFlow<Slice?> =
+        interactor.ancSlices
+            .filterIsInstance<AncSlices.Ready>()
+            .map { it.buttonSlice }
+            .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+
+    /** Call this to update [popupSlice] width in a reaction to container size change. */
+    fun onPopupSliceWidthChanged(width: Int) {
+        interactor.onPopupSliceWidthChanged(width)
+    }
+
+    /** Call this to update [buttonSlice] width in a reaction to container size change. */
+    fun onButtonSliceWidthChanged(width: Int) {
+        interactor.onButtonSliceWidthChanged(width)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index fde45d3..5af0c1f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -52,6 +52,7 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -157,7 +158,6 @@
 import org.mockito.Captor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
 import org.mockito.internal.util.reflection.FieldSetter;
@@ -809,6 +809,31 @@
     }
 
     @Test
+    public void whenFaceAuthenticated_biometricAuthenticatedCallback_beforeUpdatingFpState() {
+        // GIVEN listening for UDFPS fingerprint
+        when(mAuthController.isUdfpsSupported()).thenReturn(true);
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+        mTestableLooper.processAllMessages();
+        keyguardIsVisible();
+        final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal);
+        mKeyguardUpdateMonitor.mFingerprintCancelSignal = fpCancel;
+
+        // WHEN face is authenticated
+        when(mFaceAuthInteractor.isAuthenticated()).thenReturn(true);
+        when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(true);
+        when(mFaceAuthInteractor.isLockedOut()).thenReturn(false);
+        mKeyguardUpdateMonitor.onFaceAuthenticated(0, true);
+        mTestableLooper.processAllMessages();
+
+        // THEN verify keyguardUpdateMonitorCallback receives an onAuthenticated callback
+        // before cancelling the fingerprint request
+        InOrder inOrder = inOrder(mTestCallback, fpCancel);
+        inOrder.verify(mTestCallback).onBiometricAuthenticated(
+                eq(0), eq(BiometricSourceType.FACE), eq(true));
+        inOrder.verify(fpCancel).cancel();
+    }
+
+    @Test
     public void whenDetectFingerprint_biometricDetectCallback() {
         ArgumentCaptor<FingerprintManager.FingerprintDetectionCallback> fpDetectCallbackCaptor =
                 ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class);
@@ -2133,7 +2158,7 @@
                 null /* trustGrantedMessages */);
 
         // THEN onTrustChanged is called FIRST
-        final InOrder inOrder = Mockito.inOrder(callback);
+        final InOrder inOrder = inOrder(callback);
         inOrder.verify(callback).onTrustChanged(eq(mSelectedUserInteractor.getSelectedUserId()));
 
         // AND THEN onTrustGrantedForCurrentUser callback called
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index c20367e..d267ad4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -1274,6 +1274,28 @@
     }
 
     @Test
+    public void delayedFaceSensorLocationChangesAddsFaceScanningOverlay() {
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+        mScreenDecorations.start();
+        verifyFaceScanningViewExists(false); // face scanning view not added yet
+
+        // WHEN the sensor location is updated
+        mFaceScanningProviders = new ArrayList<>();
+        mFaceScanningProviders.add(mFaceScanningDecorProvider);
+        when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders);
+        when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(true);
+        final Point location = new Point();
+        mFakeFacePropertyRepository.setSensorLocation(location);
+        mScreenDecorations.onFaceSensorLocationChanged(location);
+        mExecutor.runAllReady();
+
+        // THEN the face scanning view is added
+        verifyFaceScanningViewExists(true);
+    }
+
+    @Test
     public void testPrivacyDotShowingListenerWorkWellWithNullParameter() {
         mPrivacyDotShowingListener.onPrivacyDotShown(null);
         mPrivacyDotShowingListener.onPrivacyDotHidden(null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 69cd592..e076420 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -181,7 +181,7 @@
             throws RemoteException {
         enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -220,7 +220,7 @@
                 mWaitAnimationDuration, /* targetScale= */ 1.0f,
                 DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationCallback);
 
-        verify(mSpyController).enableWindowMagnificationInternal(1.0f, DEFAULT_CENTER_X,
+        verify(mSpyController).updateWindowMagnificationInternal(1.0f, DEFAULT_CENTER_X,
                 DEFAULT_CENTER_Y, 0f, 0f);
         verify(mAnimationCallback).onResult(true);
     }
@@ -244,7 +244,7 @@
             advanceTimeBy(mWaitAnimationDuration);
         });
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -299,7 +299,7 @@
             advanceTimeBy(mWaitAnimationDuration);
         });
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -341,7 +341,7 @@
             advanceTimeBy(mWaitAnimationDuration);
         });
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -377,7 +377,7 @@
             advanceTimeBy(mWaitAnimationDuration);
         });
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -439,7 +439,7 @@
         enableWindowMagnificationAndWaitAnimating(
                 mWaitAnimationDuration, Float.NaN, Float.NaN, Float.NaN, mAnimationCallback2);
 
-        verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
+        verify(mSpyController, never()).updateWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
         verify(mAnimationCallback).onResult(false);
         verify(mAnimationCallback2).onResult(true);
@@ -479,7 +479,7 @@
         // Verify the method is called in
         // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once and
         // {@link Animator.AnimatorListener#onAnimationEnd} once in {@link ValueAnimator#end()}
-        verify(mSpyController, times(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, times(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -526,7 +526,7 @@
         enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, Float.NaN,
                 Float.NaN, Float.NaN, mAnimationCallback2);
 
-        verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
+        verify(mSpyController, never()).updateWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
         verify(mSpyController, never()).deleteWindowMagnification();
         verify(mAnimationCallback).onResult(false);
@@ -551,7 +551,7 @@
             advanceTimeBy(mWaitAnimationDuration);
         });
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -720,7 +720,7 @@
 
         enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
-        verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
+        verify(mSpyController, never()).updateWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
         verify(mAnimationCallback).onResult(true);
     }
@@ -733,7 +733,7 @@
         resetMockObjects();
         deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
-        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -790,7 +790,7 @@
         // Verify the method is called in
         // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once and
         // {@link Animator.AnimatorListener#onAnimationEnd} once in {@link ValueAnimator#end()}
-        verify(mSpyController, times(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, times(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -835,7 +835,7 @@
         // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once and
         // {@link Animator.AnimatorListener#onAnimationEnd} once when running the animation at
         // the final duration time.
-        verify(mSpyController, times(2)).enableWindowMagnificationInternal(
+        verify(mSpyController, times(2)).updateWindowMagnificationInternal(
                 mScaleCaptor.capture(),
                 mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                 mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
@@ -1040,17 +1040,17 @@
         }
 
         @Override
-        void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
-            super.enableWindowMagnificationInternal(scale, centerX, centerY);
-            mSpyController.enableWindowMagnificationInternal(scale, centerX, centerY);
+        void updateWindowMagnificationInternal(float scale, float centerX, float centerY) {
+            super.updateWindowMagnificationInternal(scale, centerX, centerY);
+            mSpyController.updateWindowMagnificationInternal(scale, centerX, centerY);
         }
 
         @Override
-        void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
+        void updateWindowMagnificationInternal(float scale, float centerX, float centerY,
                 float magnificationOffsetFrameRatioX, float magnificationOffsetFrameRatioY) {
-            super.enableWindowMagnificationInternal(scale, centerX, centerY,
+            super.updateWindowMagnificationInternal(scale, centerX, centerY,
                     magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY);
-            mSpyController.enableWindowMagnificationInternal(scale, centerX, centerY,
+            mSpyController.updateWindowMagnificationInternal(scale, centerX, centerY,
                     magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 6f285fb..cb42078 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -273,7 +273,7 @@
     @Test
     public void enableWindowMagnification_showControlAndNotifyBoundsChanged() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -341,7 +341,7 @@
     @Test
     public void enableWindowMagnification_systemGestureExclusionRectsIsSet() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         // Wait for Rects updated.
@@ -358,7 +358,7 @@
         mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -373,7 +373,7 @@
     @Test
     public void deleteWindowMagnification_destroyControlAndUnregisterComponentCallback() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN,
                         Float.NaN));
 
@@ -391,7 +391,7 @@
         setSystemGestureInsets();
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     bounds.bottom);
         });
         ReferenceTestUtils.waitForCondition(this::hasMagnificationOverlapFlag);
@@ -407,7 +407,7 @@
     @Test
     public void deleteWindowMagnification_notifySourceBoundsChanged() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN,
                         Float.NaN));
 
@@ -423,7 +423,7 @@
     @Test
     public void moveMagnifier_schedulesFrame() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.moveWindowMagnifier(100f, 100f);
         });
@@ -506,7 +506,7 @@
     @Test
     public void setScale_enabled_expectedValueAndUpdateStateDescription() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(2.0f,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(2.0f,
                         Float.NaN, Float.NaN));
 
         mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
@@ -539,7 +539,7 @@
         final float displayWidth = windowBounds.width();
         final PointF magnifiedCenter = new PointF(center, center + 5f);
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                     magnifiedCenter.x, magnifiedCenter.y);
             // Get the center again in case the center we set is out of screen.
             magnifiedCenter.set(mWindowMagnificationController.getCenterX(),
@@ -582,7 +582,7 @@
         final float expectedRatio = 0.5f;
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -621,8 +621,8 @@
                         preferredWindowSize.toString())
                 .commit();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController
-                    .enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN);
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
         });
 
         // Change screen density and size to trigger restoring the preferred window size
@@ -649,7 +649,7 @@
     @Test
     public void screenSizeIsChangedToLarge_enabled_defaultWindowSize() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10;
@@ -674,7 +674,7 @@
     @Test
     public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             Mockito.reset(mWindowManager);
             Mockito.reset(mMirrorWindowControl);
@@ -703,7 +703,7 @@
     @Test
     public void initializeA11yNode_enabled_expectedValues() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(2.5f, Float.NaN,
                     Float.NaN);
         });
         final View mirrorView = mWindowManager.getAttachedView();
@@ -727,7 +727,7 @@
     public void performA11yActions_visible_expectedResults() {
         final int displayId = mContext.getDisplayId();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(1.5f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(1.5f, Float.NaN,
                     Float.NaN);
         });
 
@@ -761,7 +761,7 @@
     public void performA11yActions_visible_notifyAccessibilityActionPerformed() {
         final int displayId = mContext.getDisplayId();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(2.5f, Float.NaN,
                     Float.NaN);
         });
 
@@ -774,7 +774,7 @@
     @Test
     public void windowMagnifierEditMode_performA11yClickAction_exitEditMode() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
         });
@@ -812,7 +812,7 @@
                 /* pbase= */ 1);
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -852,7 +852,7 @@
                 /* pbase= */ 1);
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -888,7 +888,7 @@
         final int startingHeight = windowBounds.height();
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -908,7 +908,7 @@
         final int startingHeight = windowBounds.height();
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -931,7 +931,7 @@
                 /* base= */ 1,
                 /* pbase= */ 1);
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -971,7 +971,7 @@
                 /* pbase= */ 1);
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -1007,7 +1007,7 @@
         final int startingSize = mMinWindowSize;
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -1027,7 +1027,7 @@
         final int startingSize = mMinWindowSize;
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -1043,7 +1043,7 @@
     @Test
     public void enableWindowMagnification_hasA11yWindowTitle() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -1054,12 +1054,12 @@
     @Test
     public void enableWindowMagnificationWithScaleLessThanOne_enabled_disabled() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(0.9f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(0.9f, Float.NaN,
                     Float.NaN);
         });
 
@@ -1078,7 +1078,7 @@
         final int newRotation = simulateRotateTheDevice();
 
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         assertEquals(newRotation, mWindowMagnificationController.mRotation);
@@ -1087,7 +1087,7 @@
     @Test
     public void enableWindowMagnification_registerComponentCallback() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN,
                         Float.NaN));
 
@@ -1098,7 +1098,7 @@
     public void onLocaleChanged_enabled_updateA11yWindowTitle() {
         final String newA11yWindowTitle = "new a11y window title";
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         final TestableResources testableResources = getContext().getOrCreateTestableResources();
@@ -1116,7 +1116,7 @@
     @Test
     public void onSingleTap_enabled_scaleAnimates() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -1143,7 +1143,7 @@
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         setSystemGestureInsets();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -1161,7 +1161,7 @@
         setSystemGestureInsets();
         mInstrumentation.runOnMainSync(
                 () -> {
-                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                    mWindowMagnificationController.updateWindowMagnificationInternal(
                             Float.NaN, Float.NaN, Float.NaN);
                 });
 
@@ -1197,7 +1197,7 @@
         setSystemGestureInsets();
         mInstrumentation.runOnMainSync(
                 () -> {
-                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                    mWindowMagnificationController.updateWindowMagnificationInternal(
                             Float.NaN, Float.NaN, Float.NaN);
                 });
 
@@ -1232,7 +1232,7 @@
         final int  expectedWindowHeight = minimumWindowSize;
         final int  expectedWindowWidth = minimumWindowSize;
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1259,7 +1259,7 @@
         final AtomicInteger actualWindowWidth = new AtomicInteger();
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                     Float.NaN, Float.NaN);
             actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
             actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
@@ -1274,7 +1274,7 @@
         final int minimumWindowSize = mResources.getDimensionPixelSize(
                 com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1294,7 +1294,7 @@
     public void setWindowSizeLargerThanScreenSize_enabled_windowSizeIsScreenSize() {
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1323,7 +1323,7 @@
 
         mInstrumentation.runOnMainSync(
                 () ->
-                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                        mWindowMagnificationController.updateWindowMagnificationInternal(
                                 Float.NaN, Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1348,7 +1348,7 @@
 
         mInstrumentation.runOnMainSync(
                 () ->
-                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                        mWindowMagnificationController.updateWindowMagnificationInternal(
                                 Float.NaN, Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1382,7 +1382,7 @@
 
         mInstrumentation.runOnMainSync(
                 () ->
-                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                        mWindowMagnificationController.updateWindowMagnificationInternal(
                                 Float.NaN, Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1408,7 +1408,7 @@
                 com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger magnificationCenterX = new AtomicInteger();
@@ -1429,7 +1429,7 @@
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         mInstrumentation.runOnMainSync(
                 () -> {
-                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                    mWindowMagnificationController.updateWindowMagnificationInternal(
                             1.5f, bounds.centerX(), bounds.centerY());
                 });
         View dragButton = getInternalView(R.id.drag_handle);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
index e9d36b8..a88654b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
@@ -282,7 +282,7 @@
     @Test
     public void enableWindowMagnification_showControlAndNotifyBoundsChanged() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -351,7 +351,7 @@
     @Test
     public void enableWindowMagnification_systemGestureExclusionRectsIsSet() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         // Wait for Rects updated.
@@ -368,7 +368,7 @@
         mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -383,7 +383,7 @@
     @Test
     public void deleteWindowMagnification_destroyControlAndUnregisterComponentCallback() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN,
                         Float.NaN));
 
@@ -401,7 +401,7 @@
         setSystemGestureInsets();
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     bounds.bottom);
         });
         ReferenceTestUtils.waitForCondition(this::hasMagnificationOverlapFlag);
@@ -417,7 +417,7 @@
     @Test
     public void deleteWindowMagnification_notifySourceBoundsChanged() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN,
                         Float.NaN));
 
@@ -433,7 +433,7 @@
     @Test
     public void moveMagnifier_schedulesFrame() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -520,7 +520,7 @@
     @Test
     public void setScale_enabled_expectedValueAndUpdateStateDescription() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(2.0f,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(2.0f,
                         Float.NaN, Float.NaN));
 
         mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
@@ -553,7 +553,7 @@
         final float displayWidth = windowBounds.width();
         final PointF magnifiedCenter = new PointF(center, center + 5f);
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                     magnifiedCenter.x, magnifiedCenter.y);
             // Get the center again in case the center we set is out of screen.
             magnifiedCenter.set(mWindowMagnificationController.getCenterX(),
@@ -596,7 +596,7 @@
         final float expectedRatio = 0.5f;
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -635,8 +635,8 @@
                         preferredWindowSize.toString())
                 .commit();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController
-                    .enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN);
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
+                    Float.NaN);
         });
 
         // Screen density and size change
@@ -663,7 +663,7 @@
     @Test
     public void screenSizeIsChangedToLarge_enabled_defaultWindowSize() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10;
@@ -688,7 +688,7 @@
     @Test
     public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             Mockito.reset(mWindowManager);
             Mockito.reset(mMirrorWindowControl);
@@ -717,7 +717,7 @@
     @Test
     public void initializeA11yNode_enabled_expectedValues() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(2.5f, Float.NaN,
                     Float.NaN);
         });
         final View mirrorView = mSurfaceControlViewHost.getView();
@@ -741,7 +741,7 @@
     public void performA11yActions_visible_expectedResults() {
         final int displayId = mContext.getDisplayId();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(1.5f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(1.5f, Float.NaN,
                     Float.NaN);
         });
 
@@ -775,7 +775,7 @@
     public void performA11yActions_visible_notifyAccessibilityActionPerformed() {
         final int displayId = mContext.getDisplayId();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(2.5f, Float.NaN,
                     Float.NaN);
         });
 
@@ -788,7 +788,7 @@
     @Test
     public void windowMagnifierEditMode_performA11yClickAction_exitEditMode() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
         });
@@ -829,7 +829,7 @@
                 /* pbase= */ 1);
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -871,7 +871,7 @@
                 /* pbase= */ 1);
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -909,7 +909,7 @@
         final int startingHeight = windowBounds.height();
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -929,7 +929,7 @@
         final int startingHeight = windowBounds.height();
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingWidth, startingHeight);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -952,7 +952,7 @@
                 /* base= */ 1,
                 /* pbase= */ 1);
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -994,7 +994,7 @@
                 /* pbase= */ 1);
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -1032,7 +1032,7 @@
         final int startingSize = mMinWindowSize;
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -1052,7 +1052,7 @@
         final int startingSize = mMinWindowSize;
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
             mWindowMagnificationController.setWindowSize(startingSize, startingSize);
             mWindowMagnificationController.setEditMagnifierSizeMode(true);
@@ -1068,7 +1068,7 @@
     @Test
     public void enableWindowMagnification_hasA11yWindowTitle() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -1079,12 +1079,12 @@
     @Test
     public void enableWindowMagnificationWithScaleLessThanOne_enabled_disabled() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(0.9f, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(0.9f, Float.NaN,
                     Float.NaN);
         });
 
@@ -1103,7 +1103,7 @@
         final int newRotation = simulateRotateTheDevice();
 
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         assertEquals(newRotation, mWindowMagnificationController.mRotation);
@@ -1112,7 +1112,7 @@
     @Test
     public void enableWindowMagnification_registerComponentCallback() {
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN,
                         Float.NaN));
 
@@ -1123,7 +1123,7 @@
     public void onLocaleChanged_enabled_updateA11yWindowTitle() {
         final String newA11yWindowTitle = "new a11y window title";
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
         final TestableResources testableResources = getContext().getOrCreateTestableResources();
@@ -1141,7 +1141,7 @@
     @Test
     public void onSingleTap_enabled_scaleAnimates() {
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -1168,7 +1168,7 @@
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         setSystemGestureInsets();
         mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
         });
 
@@ -1186,7 +1186,7 @@
         setSystemGestureInsets();
         mInstrumentation.runOnMainSync(
                 () -> {
-                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                    mWindowMagnificationController.updateWindowMagnificationInternal(
                             Float.NaN, Float.NaN, Float.NaN);
                 });
         // Wait for Region updated.
@@ -1215,7 +1215,7 @@
         setSystemGestureInsets();
         mInstrumentation.runOnMainSync(
                 () -> {
-                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                    mWindowMagnificationController.updateWindowMagnificationInternal(
                             Float.NaN, Float.NaN, Float.NaN);
                 });
         // Wait for Region updated.
@@ -1244,7 +1244,7 @@
         final int  expectedWindowHeight = minimumWindowSize;
         final int  expectedWindowWidth = minimumWindowSize;
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1271,7 +1271,7 @@
         final AtomicInteger actualWindowWidth = new AtomicInteger();
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
-            mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+            mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                     Float.NaN, Float.NaN);
             actualWindowHeight.set(mSurfaceControlViewHost.getView().getLayoutParams().height);
             actualWindowWidth.set(mSurfaceControlViewHost.getView().getLayoutParams().width);
@@ -1286,7 +1286,7 @@
         final int minimumWindowSize = mResources.getDimensionPixelSize(
                 com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1306,7 +1306,7 @@
     public void setWindowSizeLargerThanScreenSize_enabled_windowSizeIsScreenSize() {
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1335,7 +1335,7 @@
 
         mInstrumentation.runOnMainSync(
                 () ->
-                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                        mWindowMagnificationController.updateWindowMagnificationInternal(
                                 Float.NaN, Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1362,7 +1362,7 @@
 
         mInstrumentation.runOnMainSync(
                 () ->
-                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                        mWindowMagnificationController.updateWindowMagnificationInternal(
                                 Float.NaN, Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1398,7 +1398,7 @@
 
         mInstrumentation.runOnMainSync(
                 () ->
-                        mWindowMagnificationController.enableWindowMagnificationInternal(
+                        mWindowMagnificationController.updateWindowMagnificationInternal(
                                 Float.NaN, Float.NaN, Float.NaN));
 
         final AtomicInteger actualWindowHeight = new AtomicInteger();
@@ -1426,7 +1426,7 @@
                 com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         mInstrumentation.runOnMainSync(
-                () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+                () -> mWindowMagnificationController.updateWindowMagnificationInternal(Float.NaN,
                         Float.NaN, Float.NaN));
 
         final AtomicInteger magnificationCenterX = new AtomicInteger();
@@ -1447,7 +1447,7 @@
         final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
         mInstrumentation.runOnMainSync(
                 () -> {
-                    mWindowMagnificationController.enableWindowMagnificationInternal(
+                    mWindowMagnificationController.updateWindowMagnificationInternal(
                             1.5f, bounds.centerX(), bounds.centerY());
                 });
         View dragButton = getInternalView(R.id.drag_handle);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 33a6010..8f3fed7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.biometrics
 
+import android.app.ActivityTaskManager
 import android.app.admin.DevicePolicyManager
 import android.content.pm.PackageManager
 import android.hardware.biometrics.BiometricAuthenticator
@@ -44,9 +45,12 @@
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.Flags.FLAG_CONSTRAINT_BP
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
 import com.android.systemui.biometrics.data.repository.FakePromptRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
 import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor
@@ -120,10 +124,12 @@
     lateinit var selectedUserInteractor: SelectedUserInteractor
     @Mock
     private lateinit var packageManager: PackageManager
+    @Mock private lateinit var activityTaskManager: ActivityTaskManager
 
     private val testScope = TestScope(StandardTestDispatcher())
     private val fakeExecutor = FakeExecutor(FakeSystemClock())
     private val biometricPromptRepository = FakePromptRepository()
+    private val biometricStatusRepository = FakeBiometricStatusRepository()
     private val fingerprintRepository = FakeFingerprintPropertyRepository()
     private val displayStateRepository = FakeDisplayStateRepository()
     private val credentialInteractor = FakeCredentialInteractor()
@@ -143,6 +149,7 @@
     private lateinit var displayRepository: FakeDisplayRepository
     private lateinit var displayStateInteractor: DisplayStateInteractor
     private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
+    private lateinit var biometricStatusInteractor: BiometricStatusInteractor
 
     private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
     private val defaultLogoIcon = context.getDrawable(R.drawable.ic_android)
@@ -168,6 +175,8 @@
                         selectedUserInteractor,
                         testScope.backgroundScope,
                 )
+        biometricStatusInteractor =
+                BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
         // Set up default logo icon
         whenever(packageManager.getApplicationIcon(OP_PACKAGE_NAME)).thenReturn(defaultLogoIcon)
         context.setMockPackageManager(packageManager)
@@ -645,6 +654,7 @@
             promptSelectorInteractor,
             context,
             udfpsOverlayInteractor,
+            biometricStatusInteractor,
             udfpsUtils
         ),
         { credentialViewModel },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
index bf6caad..31bdde2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
@@ -1,13 +1,11 @@
 package com.android.systemui.biometrics.domain.interactor
 
-import android.view.Display
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.shared.model.DisplayRotation
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.display.data.repository.FakeDisplayRepository
-import com.android.systemui.display.data.repository.display
 import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
 import com.android.systemui.unfold.updates.FoldProvider
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -101,14 +99,11 @@
     fun isDefaultDisplayOffChanges() =
         testScope.runTest {
             val isDefaultDisplayOff by collectLastValue(interactor.isDefaultDisplayOff)
-            runCurrent()
 
-            displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_OFF)))
-            displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY)
+            displayRepository.setDefaultDisplayOff(true)
             assertThat(isDefaultDisplayOff).isTrue()
 
-            displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_ON)))
-            displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY)
+            displayRepository.setDefaultDisplayOff(false)
             assertThat(isDefaultDisplayOff).isFalse()
         }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 5b0df5d..a6c7f72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.biometrics.ui.viewmodel
 
+import android.app.ActivityTaskManager
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.content.res.Configuration
 import android.graphics.Bitmap
 import android.graphics.Point
 import android.graphics.drawable.BitmapDrawable
+import android.hardware.biometrics.BiometricFingerprintConstants
 import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT
 import android.hardware.biometrics.PromptContentItemBulletedText
 import android.hardware.biometrics.PromptContentView
@@ -40,9 +42,12 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.biometrics.UdfpsUtils
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
 import com.android.systemui.biometrics.data.repository.FakePromptRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
 import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
@@ -51,6 +56,7 @@
 import com.android.systemui.biometrics.extractAuthenticatorTypes
 import com.android.systemui.biometrics.faceSensorPropertiesInternal
 import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
 import com.android.systemui.biometrics.shared.model.BiometricModalities
 import com.android.systemui.biometrics.shared.model.BiometricModality
 import com.android.systemui.biometrics.shared.model.DisplayRotation
@@ -59,6 +65,7 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
 import com.android.systemui.res.R
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -102,6 +109,7 @@
     @Mock private lateinit var packageManager: PackageManager
     @Mock private lateinit var applicationInfoWithIcon: ApplicationInfo
     @Mock private lateinit var applicationInfoNoIcon: ApplicationInfo
+    @Mock private lateinit var activityTaskManager: ActivityTaskManager
 
     private val fakeExecutor = FakeExecutor(FakeSystemClock())
     private val testScope = TestScope()
@@ -115,9 +123,11 @@
     private lateinit var fingerprintRepository: FakeFingerprintPropertyRepository
     private lateinit var promptRepository: FakePromptRepository
     private lateinit var displayStateRepository: FakeDisplayStateRepository
+    private lateinit var biometricStatusRepository: FakeBiometricStatusRepository
     private lateinit var displayRepository: FakeDisplayRepository
     private lateinit var displayStateInteractor: DisplayStateInteractor
     private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
+    private lateinit var biometricStatusInteractor: BiometricStatusInteractor
 
     private lateinit var selector: PromptSelectorInteractor
     private lateinit var viewModel: PromptViewModel
@@ -157,6 +167,9 @@
                 selectedUserInteractor,
                 testScope.backgroundScope
             )
+        biometricStatusRepository = FakeBiometricStatusRepository()
+        biometricStatusInteractor =
+            BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
         selector =
             PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
         selector.resetPrompt()
@@ -178,6 +191,7 @@
                 selector,
                 mContext,
                 udfpsOverlayInteractor,
+                biometricStatusInteractor,
                 udfpsUtils
             )
         iconViewModel = viewModel.iconViewModel
@@ -1053,8 +1067,7 @@
     fun auto_confirm_authentication_when_finger_down() = runGenericTest {
         val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
 
-        // No icon button when face only, can't confirm before auth
-        if (!testCase.isFaceOnly) {
+        if (testCase.isCoex) {
             viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_DOWN))
         }
         viewModel.showAuthenticated(testCase.authenticatedModality, 0)
@@ -1069,14 +1082,18 @@
         assertThat(canTryAgain).isFalse()
         assertThat(authenticated?.isAuthenticated).isTrue()
 
-        if (testCase.isFaceOnly && expectConfirmation) {
-            assertThat(size).isEqualTo(PromptSize.MEDIUM)
-            assertButtonsVisible(
-                cancel = true,
-                confirm = true,
-            )
+        if (expectConfirmation) {
+            if (testCase.isFaceOnly) {
+                assertThat(size).isEqualTo(PromptSize.MEDIUM)
+                assertButtonsVisible(
+                    cancel = true,
+                    confirm = true,
+                )
 
-            viewModel.confirmAuthenticated()
+                viewModel.confirmAuthenticated()
+            } else if (testCase.isCoex) {
+                assertThat(authenticated?.isAuthenticatedAndConfirmed).isTrue()
+            }
             assertThat(message).isEqualTo(PromptMessage.Empty)
             assertButtonsVisible()
         }
@@ -1086,8 +1103,7 @@
     fun cannot_auto_confirm_authentication_when_finger_up() = runGenericTest {
         val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
 
-        // No icon button when face only, can't confirm before auth
-        if (!testCase.isFaceOnly) {
+        if (testCase.isCoex) {
             viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_DOWN))
             viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_UP))
         }
@@ -1413,6 +1429,12 @@
             packageName = packageName,
         )
 
+        biometricStatusRepository.setFingerprintAcquiredStatus(
+            AcquiredFingerprintAuthenticationStatus(
+                AuthenticationReason.BiometricPromptAuthentication,
+                BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN
+            )
+        )
         // put the view model in the initial authenticating state, unless explicitly skipped
         val startMode =
             when {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 806930d..68d49c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -22,6 +22,7 @@
 import android.testing.TestableLooper
 import android.view.Display
 import android.view.Display.TYPE_EXTERNAL
+import android.view.Display.TYPE_INTERNAL
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.FlowValue
@@ -427,6 +428,35 @@
             assertThat(display!!.type).isEqualTo(TYPE_EXTERNAL)
         }
 
+    @Test
+    fun defaultDisplayOff_changes() =
+        testScope.runTest {
+            val defaultDisplayOff by latestDefaultDisplayOffFlowValue()
+            setDisplays(
+                listOf(
+                    display(
+                        type = TYPE_INTERNAL,
+                        id = Display.DEFAULT_DISPLAY,
+                        state = Display.STATE_OFF
+                    )
+                )
+            )
+            displayListener.value.onDisplayChanged(Display.DEFAULT_DISPLAY)
+            assertThat(defaultDisplayOff).isTrue()
+
+            setDisplays(
+                listOf(
+                    display(
+                        type = TYPE_INTERNAL,
+                        id = Display.DEFAULT_DISPLAY,
+                        state = Display.STATE_ON
+                    )
+                )
+            )
+            displayListener.value.onDisplayChanged(Display.DEFAULT_DISPLAY)
+            assertThat(defaultDisplayOff).isFalse()
+        }
+
     private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }
 
     // Wrapper to capture the displayListener.
@@ -436,6 +466,13 @@
         return flowValue
     }
 
+    // Wrapper to capture the displayListener.
+    private fun TestScope.latestDefaultDisplayOffFlowValue(): FlowValue<Boolean?> {
+        val flowValue = collectLastValue(displayRepository.defaultDisplayOff)
+        captureAddedRemovedListener()
+        return flowValue
+    }
+
     private fun TestScope.lastPendingDisplay(): FlowValue<DisplayRepository.PendingDisplay?> {
         val flowValue = collectLastValue(displayRepository.pendingDisplay)
         captureAddedRemovedListener()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 11ec417f..318227f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -91,6 +91,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dreams.ui.viewmodel.DreamViewModel;
 import com.android.systemui.dump.DumpManager;
@@ -219,6 +220,7 @@
 
     private @Mock CoroutineDispatcher mDispatcher;
     private @Mock DreamViewModel mDreamViewModel;
+    private @Mock CommunalTransitionViewModel mCommunalTransitionViewModel;
     private @Mock SystemPropertiesHelper mSystemPropertiesHelper;
     private @Mock SceneContainerFlags mSceneContainerFlags;
 
@@ -241,6 +243,10 @@
                 .thenReturn(mock(Flow.class));
         when(mDreamViewModel.getTransitionEnded())
                 .thenReturn(mock(Flow.class));
+        when(mCommunalTransitionViewModel.getShowByDefault())
+                .thenReturn(mock(Flow.class));
+        when(mCommunalTransitionViewModel.getTransitionFromOccludedEnded())
+                .thenReturn(mock(Flow.class));
         when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(mDefaultUserId);
         when(mSelectedUserInteractor.getSelectedUserId(anyBoolean())).thenReturn(mDefaultUserId);
         mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(
@@ -1229,6 +1235,7 @@
                 mSystemClock,
                 mDispatcher,
                 () -> mDreamViewModel,
+                () -> mCommunalTransitionViewModel,
                 mSystemPropertiesHelper,
                 () -> mock(WindowManagerLockscreenVisibilityManager.class),
                 mSelectedUserInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 2c0a51835..e155a1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -27,6 +27,8 @@
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.dock.DockManager
+import com.android.systemui.dock.fakeDockManager
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeCommandQueue
@@ -108,6 +110,7 @@
 
     private val powerInteractor = kosmos.powerInteractor
     private val communalInteractor = kosmos.communalInteractor
+    private val dockManager = kosmos.fakeDockManager
 
     @Before
     fun setUp() {
@@ -1230,6 +1233,38 @@
         }
 
     @Test
+    fun occludedToGlanceableHubWhenDocked() =
+        testScope.runTest {
+            // GIVEN a device on lockscreen
+            keyguardRepository.setKeyguardShowing(true)
+            runCurrent()
+
+            // GIVEN a prior transition has run to OCCLUDED
+            runTransitionAndSetWakefulness(KeyguardState.GLANCEABLE_HUB, KeyguardState.OCCLUDED)
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            // GIVEN device is docked
+            dockManager.setIsDocked(true)
+            dockManager.setDockEvent(DockManager.STATE_DOCKED)
+
+            // WHEN occlusion ends
+            keyguardRepository.setKeyguardOccluded(false)
+            runCurrent()
+
+            // THEN a transition to GLANCEABLE_HUB should occur
+            assertThat(transitionRepository)
+                .startedTransition(
+                    ownerName = FromOccludedTransitionInteractor::class.simpleName,
+                    from = KeyguardState.OCCLUDED,
+                    to = KeyguardState.GLANCEABLE_HUB,
+                    animatorAssertion = { it.isNotNull() },
+                )
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
     fun occludedToAlternateBouncer() =
         testScope.runTest {
             // GIVEN a prior transition has run to OCCLUDED
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index 8b79fa4..2536078 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -258,6 +258,7 @@
             colorBackground = 0,
             isForegroundTask = isForegroundTask,
             userType = RecentTask.UserType.STANDARD,
+            splitBounds = null,
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
index dd62112..6ac86f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
@@ -195,6 +195,7 @@
             colorBackground = null,
             isForegroundTask = false,
             userType = userType,
+            splitBounds = null
         )
 
     private fun createSingleTask(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
index a84008b..f4c5ccf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
@@ -18,22 +18,28 @@
 
 import android.app.ActivityOptions
 import android.app.IActivityTaskManager
+import android.graphics.Rect
 import android.os.Bundle
 import android.view.View
 import android.view.ViewGroup
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags.FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX
+import com.android.systemui.Flags.FLAG_PSS_APP_SELECTOR_RECENTS_SPLIT_SCREEN
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.util.mockito.mock
+import com.android.wm.shell.splitscreen.SplitScreen
+import com.android.wm.shell.util.SplitBounds
 import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
 import org.junit.Rule
 import org.junit.Test
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.verify
 
 @SmallTest
@@ -46,9 +52,10 @@
     private val taskViewSizeProvider = mock<TaskPreviewSizeProvider>()
     private val activityTaskManager = mock<IActivityTaskManager>()
     private val resultHandler = mock<MediaProjectionAppSelectorResultHandler>()
+    private val splitScreen = Optional.of(mock<SplitScreen>())
     private val bundleCaptor = ArgumentCaptor.forClass(Bundle::class.java)
 
-    private val task =
+    private val fullScreenTask =
         RecentTask(
             taskId = 123,
             displayId = 456,
@@ -58,6 +65,20 @@
             colorBackground = null,
             isForegroundTask = false,
             userType = RecentTask.UserType.STANDARD,
+            splitBounds = null
+        )
+
+    private val splitScreenTask =
+        RecentTask(
+            taskId = 123,
+            displayId = 456,
+            userId = 789,
+            topActivityComponent = null,
+            baseIntentComponent = null,
+            colorBackground = null,
+            isForegroundTask = false,
+            userType = RecentTask.UserType.STANDARD,
+            splitBounds = SplitBounds(Rect(), Rect(), 0, 0, 0)
         )
 
     private val taskView =
@@ -70,61 +91,97 @@
             tasksAdapterFactory,
             taskViewSizeProvider,
             activityTaskManager,
-            resultHandler
+            resultHandler,
+            splitScreen,
         )
 
     @Test
-    fun onRecentAppClicked_taskWithSameIdIsStartedFromRecents() {
-        controller.onRecentAppClicked(task, taskView)
+    fun onRecentAppClicked_fullScreenTaskWithSameIdIsStartedFromRecents() {
+        controller.onRecentAppClicked(fullScreenTask, taskView)
 
-        verify(activityTaskManager).startActivityFromRecents(eq(task.taskId), any())
+        verify(activityTaskManager).startActivityFromRecents(eq(fullScreenTask.taskId), any())
+    }
+
+    @Test
+    fun onRecentAppClicked_splitScreenTaskWithSameIdIsStartedFromRecents() {
+        mSetFlagsRule.enableFlags(FLAG_PSS_APP_SELECTOR_RECENTS_SPLIT_SCREEN)
+        controller.onRecentAppClicked(splitScreenTask, taskView)
+
+        verify(splitScreen.get())
+            .startTasks(
+                eq(splitScreenTask.taskId),
+                any(),
+                anyInt(),
+                any(),
+                anyInt(),
+                anyInt(),
+                any(),
+                any()
+            )
     }
 
     @Test
     fun onRecentAppClicked_launchDisplayIdIsSet() {
-        controller.onRecentAppClicked(task, taskView)
+        controller.onRecentAppClicked(fullScreenTask, taskView)
 
-        assertThat(getStartedTaskActivityOptions().launchDisplayId).isEqualTo(task.displayId)
+        assertThat(getStartedTaskActivityOptions(fullScreenTask.taskId).launchDisplayId)
+            .isEqualTo(fullScreenTask.displayId)
     }
 
     @Test
-    fun onRecentAppClicked_taskNotInForeground_usesScaleUpAnimation() {
-        controller.onRecentAppClicked(task, taskView)
+    fun onRecentAppClicked_fullScreenTaskNotInForeground_usesScaleUpAnimation() {
+        assertThat(fullScreenTask.isForegroundTask).isFalse()
+        controller.onRecentAppClicked(fullScreenTask, taskView)
 
-        assertThat(getStartedTaskActivityOptions().animationType)
+        assertThat(getStartedTaskActivityOptions(fullScreenTask.taskId).animationType)
             .isEqualTo(ActivityOptions.ANIM_SCALE_UP)
     }
 
     @Test
-    fun onRecentAppClicked_taskInForeground_flagOff_usesScaleUpAnimation() {
+    fun onRecentAppClicked_fullScreenTaskInForeground_flagOff_usesScaleUpAnimation() {
         mSetFlagsRule.disableFlags(FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX)
 
-        controller.onRecentAppClicked(task, taskView)
+        controller.onRecentAppClicked(fullScreenTask, taskView)
 
-        assertThat(getStartedTaskActivityOptions().animationType)
+        assertThat(getStartedTaskActivityOptions(fullScreenTask.taskId).animationType)
             .isEqualTo(ActivityOptions.ANIM_SCALE_UP)
     }
 
     @Test
-    fun onRecentAppClicked_taskInForeground_flagOn_usesDefaultAnimation() {
+    fun onRecentAppClicked_fullScreenTaskInForeground_flagOn_usesDefaultAnimation() {
         mSetFlagsRule.enableFlags(FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX)
-        val foregroundTask = task.copy(isForegroundTask = true)
+        assertForegroundTaskUsesDefaultCloseAnimation(fullScreenTask)
+    }
 
+    @Test
+    fun onRecentAppClicked_splitScreenTaskInForeground_flagOn_usesDefaultAnimation() {
+        mSetFlagsRule.enableFlags(
+            FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX,
+            FLAG_PSS_APP_SELECTOR_RECENTS_SPLIT_SCREEN
+        )
+        assertForegroundTaskUsesDefaultCloseAnimation(splitScreenTask)
+    }
+
+    private fun assertForegroundTaskUsesDefaultCloseAnimation(task: RecentTask) {
+        val foregroundTask = task.copy(isForegroundTask = true)
         controller.onRecentAppClicked(foregroundTask, taskView)
 
         expect
-            .that(getStartedTaskActivityOptions().animationType)
+            .that(getStartedTaskActivityOptions(foregroundTask.taskId).animationType)
             .isEqualTo(ActivityOptions.ANIM_CUSTOM)
-        expect.that(getStartedTaskActivityOptions().overrideTaskTransition).isTrue()
         expect
-            .that(getStartedTaskActivityOptions().customExitResId)
+            .that(getStartedTaskActivityOptions(foregroundTask.taskId).overrideTaskTransition)
+            .isTrue()
+        expect
+            .that(getStartedTaskActivityOptions(foregroundTask.taskId).customExitResId)
             .isEqualTo(com.android.internal.R.anim.resolver_close_anim)
-        expect.that(getStartedTaskActivityOptions().customEnterResId).isEqualTo(0)
+        expect
+            .that(getStartedTaskActivityOptions(foregroundTask.taskId).customEnterResId)
+            .isEqualTo(0)
     }
 
-    private fun getStartedTaskActivityOptions(): ActivityOptions {
-        verify(activityTaskManager)
-            .startActivityFromRecents(eq(task.taskId), bundleCaptor.capture())
+    private fun getStartedTaskActivityOptions(taskId: Int): ActivityOptions {
+        verify(activityTaskManager).startActivityFromRecents(eq(taskId), bundleCaptor.capture())
         return ActivityOptions.fromBundle(bundleCaptor.value)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
index bde821b..853e50a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.systemui.screenshot
 
-import android.app.Notification
-import android.app.PendingIntent
 import android.content.Intent
 import android.net.Uri
 import android.os.Process
@@ -27,8 +25,6 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.clipboardoverlay.EditTextActivity
-import com.android.systemui.res.R
 import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
@@ -41,10 +37,7 @@
 import org.junit.Before
 import org.junit.runner.RunWith
 import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.kotlin.any
-import org.mockito.kotlin.never
 import org.mockito.kotlin.verify
-import org.mockito.kotlin.whenever
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
@@ -52,7 +45,6 @@
     private val actionExecutor = mock<ActionExecutor>()
     private val accessibilityManager = mock<AccessibilityManager>()
     private val uiEventLogger = mock<UiEventLogger>()
-    private val smartActionsProvider = mock<SmartActionsProvider>()
 
     private val request = ScreenshotData.forTesting()
     private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0)
@@ -119,42 +111,10 @@
         assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_CHOOSER)
     }
 
-    @Test
-    fun quickShareTapped_wrapsAndSendsIntent() = runTest {
-        val quickShare =
-            Notification.Action(
-                R.drawable.ic_screenshot_edit,
-                "TestQuickShare",
-                PendingIntent.getActivity(
-                    context,
-                    0,
-                    Intent(context, EditTextActivity::class.java),
-                    PendingIntent.FLAG_MUTABLE
-                )
-            )
-        whenever(smartActionsProvider.requestQuickShare(any(), any(), any())).then {
-            (it.getArgument(2) as ((Notification.Action) -> Unit)).invoke(quickShare)
-        }
-        whenever(smartActionsProvider.wrapIntent(any(), any(), any(), any())).thenAnswer {
-            (it.getArgument(0) as Notification.Action).actionIntent
-        }
-        actionsProvider = createActionsProvider()
-
-        viewModel.actions.value[2].onClicked?.invoke()
-        verify(uiEventLogger, never())
-            .log(eq(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED), any(), any())
-        verify(smartActionsProvider, never()).wrapIntent(any(), any(), any(), any())
-        actionsProvider.setCompletedScreenshot(validResult)
-        verify(smartActionsProvider)
-            .wrapIntent(eq(quickShare), eq(validResult.uri), eq(validResult.subject), eq("testid"))
-        verify(uiEventLogger).log(eq(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED), eq(0), eq(""))
-    }
-
     private fun createActionsProvider(): ScreenshotActionsProvider {
         return DefaultScreenshotActionsProvider(
             context,
             viewModel,
-            smartActionsProvider,
             uiEventLogger,
             request,
             "testid",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 69e0db9..54a6523 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -138,7 +138,7 @@
                 mHeadsUpManager,
                 mPowerInteractor,
                 mActiveNotificationsInteractor,
-                mKosmos.getFakeSceneContainerFlags(),
+                mKosmos.getSceneContainerFlags(),
                 () -> mKosmos.getSceneInteractor());
         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
 
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 fe0d9d0..db053d8 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,7 +23,6 @@
 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;
@@ -97,7 +96,6 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 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 org.junit.Before;
@@ -182,7 +180,7 @@
                 mHeadsUpManager,
                 PowerInteractorFactory.create().getPowerInteractor(),
                 mActiveNotificationsInteractor,
-                mKosmos.getFakeSceneContainerFlags(),
+                mKosmos.getSceneContainerFlags(),
                 () -> mKosmos.getSceneInteractor()
         );
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 05fd63e..dc3db4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -172,7 +172,7 @@
                 mKeyguardRepository,
                 mCommandQueue,
                 PowerInteractorFactory.create().getPowerInteractor(),
-                mKosmos.getFakeSceneContainerFlags(),
+                mKosmos.getSceneContainerFlags(),
                 new FakeKeyguardBouncerRepository(),
                 new ConfigurationInteractor(new FakeConfigurationRepository()),
                 new FakeShadeRepository(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 34605fe..f8c01e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -76,8 +76,6 @@
 import com.android.systemui.bouncer.ui.BouncerViewDelegate;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
@@ -145,7 +143,6 @@
     @Mock private SysUIUnfoldComponent mSysUiUnfoldComponent;
     @Mock private DreamOverlayStateController mDreamOverlayStateController;
     @Mock private LatencyTracker mLatencyTracker;
-    private FakeFeatureFlags mFeatureFlags;
     @Mock private KeyguardSecurityModel mKeyguardSecurityModel;
     @Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
     @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@@ -188,11 +185,10 @@
                 .thenReturn(mKeyguardMessageAreaController);
         when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
         when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback);
-        mFeatureFlags = new FakeFeatureFlags();
-        mFeatureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false);
         mSetFlagsRule.disableFlags(
                 com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR,
-                com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
+                com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
+                com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT
         );
 
         when(mNotificationShadeWindowController.getWindowRootView())
@@ -218,7 +214,6 @@
                         () -> mShadeController,
                         mLatencyTracker,
                         mKeyguardSecurityModel,
-                        mFeatureFlags,
                         mPrimaryBouncerCallbackInteractor,
                         mPrimaryBouncerInteractor,
                         mBouncerView,
@@ -728,7 +723,6 @@
                         () -> mShadeController,
                         mLatencyTracker,
                         mKeyguardSecurityModel,
-                        mFeatureFlags,
                         mPrimaryBouncerCallbackInteractor,
                         mPrimaryBouncerInteractor,
                         mBouncerView,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index ae34256..69536c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -30,7 +30,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.data.repository.FakeKeyguardStatusBarRepository
@@ -60,7 +60,7 @@
             keyguardRepository,
             mock<CommandQueue>(),
             PowerInteractorFactory.create().powerInteractor,
-            kosmos.fakeSceneContainerFlags,
+            kosmos.sceneContainerFlags,
             FakeKeyguardBouncerRepository(),
             ConfigurationInteractor(FakeConfigurationRepository()),
             FakeShadeRepository(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
index 7a83cfe..6f58941 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
@@ -23,14 +23,8 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.animation.AnimatorTestRule
 import com.android.systemui.model.SysUiStateTest
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.EASE_IN
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.EASE_OUT
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.MAIN
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.NOT_PLAYING
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationStateChangedCallback
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.PaintDrawCallback
-import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.RenderEffectDrawCallback
+import com.android.systemui.surfaceeffects.PaintDrawCallback
+import com.android.systemui.surfaceeffects.RenderEffectDrawCallback
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig
 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader
 import com.google.common.truth.Truth.assertThat
@@ -50,8 +44,8 @@
         var paintFromCallback: Paint? = null
         val drawCallback =
             object : PaintDrawCallback {
-                override fun onDraw(loadingPaint: Paint) {
-                    paintFromCallback = loadingPaint
+                override fun onDraw(paint: Paint) {
+                    paintFromCallback = paint
                 }
             }
         val loadingEffect =
@@ -75,8 +69,8 @@
         var renderEffectFromCallback: RenderEffect? = null
         val drawCallback =
             object : RenderEffectDrawCallback {
-                override fun onDraw(loadingRenderEffect: RenderEffect) {
-                    renderEffectFromCallback = loadingRenderEffect
+                override fun onDraw(renderEffect: RenderEffect) {
+                    renderEffectFromCallback = renderEffect
                 }
             }
         val loadingEffect =
@@ -98,16 +92,19 @@
     @Test
     fun play_animationStateChangesInOrder() {
         val config = TurbulenceNoiseAnimationConfig()
-        val states = mutableListOf(NOT_PLAYING)
+        val states = mutableListOf(LoadingEffect.AnimationState.NOT_PLAYING)
         val stateChangedCallback =
-            object : AnimationStateChangedCallback {
-                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
+            object : LoadingEffect.AnimationStateChangedCallback {
+                override fun onStateChanged(
+                    oldState: LoadingEffect.AnimationState,
+                    newState: LoadingEffect.AnimationState
+                ) {
                     states.add(newState)
                 }
             }
         val drawCallback =
             object : PaintDrawCallback {
-                override fun onDraw(loadingPaint: Paint) {}
+                override fun onDraw(paint: Paint) {}
             }
         val loadingEffect =
             LoadingEffect(
@@ -125,7 +122,14 @@
         animatorTestRule.advanceTimeBy(config.easeOutDuration.toLong())
         animatorTestRule.advanceTimeBy(500)
 
-        assertThat(states).containsExactly(NOT_PLAYING, EASE_IN, MAIN, EASE_OUT, NOT_PLAYING)
+        assertThat(states)
+            .containsExactly(
+                LoadingEffect.AnimationState.NOT_PLAYING,
+                LoadingEffect.AnimationState.EASE_IN,
+                LoadingEffect.AnimationState.MAIN,
+                LoadingEffect.AnimationState.EASE_OUT,
+                LoadingEffect.AnimationState.NOT_PLAYING
+            )
     }
 
     @Test
@@ -133,16 +137,22 @@
         val config = TurbulenceNoiseAnimationConfig()
         var numPlay = 0
         val stateChangedCallback =
-            object : AnimationStateChangedCallback {
-                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
-                    if (oldState == NOT_PLAYING && newState == EASE_IN) {
+            object : LoadingEffect.AnimationStateChangedCallback {
+                override fun onStateChanged(
+                    oldState: LoadingEffect.AnimationState,
+                    newState: LoadingEffect.AnimationState
+                ) {
+                    if (
+                        oldState == LoadingEffect.AnimationState.NOT_PLAYING &&
+                            newState == LoadingEffect.AnimationState.EASE_IN
+                    ) {
                         numPlay++
                     }
                 }
             }
         val drawCallback =
             object : PaintDrawCallback {
-                override fun onDraw(loadingPaint: Paint) {}
+                override fun onDraw(paint: Paint) {}
             }
         val loadingEffect =
             LoadingEffect(
@@ -172,9 +182,15 @@
             }
         var isFinished = false
         val stateChangedCallback =
-            object : AnimationStateChangedCallback {
-                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
-                    if (oldState == EASE_OUT && newState == NOT_PLAYING) {
+            object : LoadingEffect.AnimationStateChangedCallback {
+                override fun onStateChanged(
+                    oldState: LoadingEffect.AnimationState,
+                    newState: LoadingEffect.AnimationState
+                ) {
+                    if (
+                        oldState == LoadingEffect.AnimationState.EASE_OUT &&
+                            newState == LoadingEffect.AnimationState.NOT_PLAYING
+                    ) {
                         isFinished = true
                     }
                 }
@@ -205,13 +221,19 @@
         val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)
         val drawCallback =
             object : PaintDrawCallback {
-                override fun onDraw(loadingPaint: Paint) {}
+                override fun onDraw(paint: Paint) {}
             }
         var isFinished = false
         val stateChangedCallback =
-            object : AnimationStateChangedCallback {
-                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
-                    if (oldState == MAIN && newState == NOT_PLAYING) {
+            object : LoadingEffect.AnimationStateChangedCallback {
+                override fun onStateChanged(
+                    oldState: LoadingEffect.AnimationState,
+                    newState: LoadingEffect.AnimationState
+                ) {
+                    if (
+                        oldState == LoadingEffect.AnimationState.MAIN &&
+                            newState == LoadingEffect.AnimationState.NOT_PLAYING
+                    ) {
                         isFinished = true
                     }
                 }
@@ -242,7 +264,7 @@
             )
         val drawCallback =
             object : PaintDrawCallback {
-                override fun onDraw(loadingPaint: Paint) {}
+                override fun onDraw(paint: Paint) {}
             }
         val loadingEffect =
             LoadingEffect(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt
index 9cbe633..2ae6f542 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.biometrics.ui.viewmodel
 
 import android.content.applicationContext
+import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor
 import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
 import com.android.systemui.biometrics.domain.interactor.promptSelectorInteractor
 import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
@@ -30,6 +31,7 @@
         promptSelectorInteractor = promptSelectorInteractor,
         context = applicationContext,
         udfpsOverlayInteractor = udfpsOverlayInteractor,
+        biometricStatusInteractor = biometricStatusInteractor,
         udfpsUtils = udfpsUtils
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 8866fd3..4b6ef37 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.communal.data.repository.communalRepository
 import com.android.systemui.communal.data.repository.communalWidgetRepository
 import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
+import com.android.systemui.dock.fakeDockManager
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -33,7 +34,7 @@
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.plugins.activityStarter
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import com.android.systemui.settings.userTracker
 import com.android.systemui.smartspace.data.repository.smartspaceRepository
 import com.android.systemui.user.data.repository.fakeUserRepository
@@ -54,11 +55,12 @@
         userTracker = userTracker,
         activityStarter = activityStarter,
         userManager = userManager,
+        dockManager = fakeDockManager,
         logBuffer = logcatLogBuffer("CommunalInteractor"),
         tableLogBuffer = mock(),
         communalSettingsInteractor = communalSettingsInteractor,
         sceneInteractor = sceneInteractor,
-        sceneContainerFlags = fakeSceneContainerFlags,
+        sceneContainerFlags = sceneContainerFlags,
     )
 }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt
index 2396722..e36ddc1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.communal.ui.viewmodel
 
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.viewmodel.dreamingToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel
@@ -27,9 +29,13 @@
 val Kosmos.communalTransitionViewModel by
     Kosmos.Fixture {
         CommunalTransitionViewModel(
-            glanceableHubToLockscreenTransitionViewModel,
-            lockscreenToGlanceableHubTransitionViewModel,
-            dreamingToGlanceableHubTransitionViewModel,
-            glanceableHubToDreamingTransitionViewModel,
+            glanceableHubToLockscreenTransitionViewModel =
+                glanceableHubToLockscreenTransitionViewModel,
+            lockscreenToGlanceableHubTransitionViewModel =
+                lockscreenToGlanceableHubTransitionViewModel,
+            dreamToGlanceableHubTransitionViewModel = dreamingToGlanceableHubTransitionViewModel,
+            glanceableHubToDreamTransitionViewModel = glanceableHubToDreamingTransitionViewModel,
+            communalInteractor = communalInteractor,
+            keyguardTransitionInteractor = keyguardTransitionInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index 0fc0a3c..6c3cf91 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -23,6 +23,8 @@
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import org.mockito.Mockito.`when` as whenever
 
 /** Creates a mock display. */
@@ -69,12 +71,20 @@
     override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?>
         get() = pendingDisplayFlow
 
+    val _defaultDisplayOff: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    override val defaultDisplayOff: Flow<Boolean>
+        get() = _defaultDisplayOff.asStateFlow()
+
     override val displayAdditionEvent: Flow<Display?>
         get() = displayAdditionEventFlow
 
     private val _displayChangeEvent = MutableSharedFlow<Int>(replay = 1)
     override val displayChangeEvent: Flow<Int> = _displayChangeEvent
     suspend fun emitDisplayChangeEvent(displayId: Int) = _displayChangeEvent.emit(displayId)
+
+    fun setDefaultDisplayOff(defaultDisplayOff: Boolean) {
+        _defaultDisplayOff.value = defaultDisplayOff
+    }
 }
 
 @Module
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java
similarity index 94%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFake.java
rename to packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java
index 3754062..b99310b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFake.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java
@@ -49,6 +49,7 @@
         return mDocked;
     }
 
+    /** Sets the docked state */
     public void setIsDocked(boolean docked) {
         mDocked = docked;
     }
@@ -58,6 +59,7 @@
         return false;
     }
 
+    /** Notifies callbacks of dock state change */
     public void setDockEvent(int event) {
         mCallback.onEvent(event);
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFakeKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFakeKosmos.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFakeKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFakeKosmos.kt
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/BrokenWithSceneContainer.kt
similarity index 61%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/flags/BrokenWithSceneContainer.kt
index f6140f5..29b088b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/BrokenWithSceneContainer.kt
@@ -14,9 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.credentialmanager.common
+package com.android.systemui.flags
 
-enum class FlowType {
-    GET,
-    CREATE
-}
\ No newline at end of file
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
+
+/**
+ * This is used by [SceneContainerRule] to assert that the test is broken when
+ * [FLAG_SCENE_CONTAINER] is enabled.
+ */
+@Retention(AnnotationRetention.RUNTIME)
+@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
+annotation class BrokenWithSceneContainer(val bugId: Int)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
index c1d2ad6..e83205c5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
@@ -18,12 +18,14 @@
 
 import android.platform.test.annotations.EnableFlags
 import com.android.systemui.Flags.FLAG_COMPOSE_LOCKSCREEN
+import com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR
 import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
 import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
 import com.android.systemui.Flags.FLAG_MEDIA_IN_SCENE_CONTAINER
 import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
 import com.android.systemui.Flags.FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR
 import com.android.systemui.Flags.FLAG_PREDICTIVE_BACK_SYSUI
+import com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT
 import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 
 /**
@@ -39,6 +41,8 @@
     FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR,
     FLAG_PREDICTIVE_BACK_SYSUI,
     FLAG_SCENE_CONTAINER,
+    FLAG_DEVICE_ENTRY_UDFPS_REFACTOR,
+    FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,
 )
 @Retention(AnnotationRetention.RUNTIME)
 @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerFlagParameterization.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerFlagParameterization.kt
new file mode 100644
index 0000000..4e24233
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerFlagParameterization.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.systemui.flags
+
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
+
+/** The name of the one flag to be disabled for OFF parameterization */
+private const val flagNameToDisable = FLAG_SCENE_CONTAINER
+
+/** Cache of the flags to be enabled for ON parameterization */
+private val flagNamesToEnable =
+    EnableSceneContainer::class.java.getAnnotation(EnableFlags::class.java)!!.value.toList()
+
+/**
+ * Provides one or two copies of this [FlagsParameterization]; one which disabled
+ * [FLAG_SCENE_CONTAINER] and if none of the dependencies of it are disabled by this, a second copy
+ * which enables [FLAG_SCENE_CONTAINER] and all the dependencies (just like [EnableSceneContainer]).
+ */
+fun FlagsParameterization.andSceneContainer(): Sequence<FlagsParameterization> = sequence {
+    check(flagNameToDisable !in mOverrides) {
+        "Can't add $flagNameToDisable to FlagsParameterization: $this"
+    }
+    yield(FlagsParameterization(mOverrides + mapOf(flagNameToDisable to false)))
+    if (flagNamesToEnable.all { mOverrides[it] != false }) {
+        // Can't add the parameterization of enabling SceneContainerFlag to a parameterization that
+        // explicitly disables one of the prerequisite flags.
+        yield(FlagsParameterization(mOverrides + flagNamesToEnable.associateWith { true }))
+    }
+}
+
+/**
+ * Doubles (roughly; see below) the given list of [FlagsParameterization] for enabling and disabling
+ * SceneContainerFlag.
+ *
+ * The input parameterization may not define [FLAG_SCENE_CONTAINER].
+ *
+ * Any [FlagsParameterization] which disables any flag that is a dependency of
+ * [FLAG_SCENE_CONTAINER], will not add a state for enabling, and the state will simply be converted
+ * to one which disables. Just like [EnableSceneContainer], enabling will also enable all the other
+ * dependencies. For any flag parameterization where a dependency is disabled, an "enabled"
+ * parameterization is inconsistent, so it will not be added.
+ */
+fun List<FlagsParameterization>.andSceneContainer(): List<FlagsParameterization> =
+    flatMap { it.andSceneContainer() }.toList()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt
index 775ad14..9ec1481 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import org.junit.Assert
+import org.junit.AssumptionViolatedException
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
@@ -33,10 +34,7 @@
         return object : Statement() {
             @Throws(Throwable::class)
             override fun evaluate() {
-                val hasAnnotation =
-                    description?.testClass?.getAnnotation(EnableSceneContainer::class.java) !=
-                        null || description?.getAnnotation(EnableSceneContainer::class.java) != null
-                if (hasAnnotation) {
+                if (description.hasAnnotation<EnableSceneContainer>()) {
                     Assert.assertTrue(
                         "SceneContainerFlag.isEnabled is false:" +
                             "\n * Did you forget to add a new aconfig flag dependency in" +
@@ -45,8 +43,31 @@
                         SceneContainerFlag.isEnabled
                     )
                 }
+                if (
+                    description.hasAnnotation<BrokenWithSceneContainer>() &&
+                        SceneContainerFlag.isEnabled
+                ) {
+                    runCatching { base?.evaluate() }
+                        .onFailure { exception ->
+                            if (exception is AssumptionViolatedException) {
+                                throw AssertionError(
+                                    "This is marked @BrokenWithSceneContainer, but was skipped.",
+                                    exception
+                                )
+                            }
+                            throw AssumptionViolatedException("Test is still broken", exception)
+                        }
+                    throw AssertionError(
+                        "HOORAY! You fixed a test that was marked @BrokenWithSceneContainer. " +
+                            "Remove the obsolete annotation to fix this failure."
+                    )
+                }
                 base?.evaluate()
             }
         }
     }
+
+    inline fun <reified T : Annotation> Description?.hasAnnotation(): Boolean =
+        this?.testClass?.getAnnotation(T::class.java) != null ||
+            this?.getAnnotation(T::class.java) != null
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
new file mode 100644
index 0000000..2c6d44f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
@@ -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.systemui.keyguard.domain.interactor
+
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.keyguardDismissActionInteractor by
+    Kosmos.Fixture {
+        KeyguardDismissActionInteractor(
+            repository = keyguardRepository,
+            transitionInteractor = keyguardTransitionInteractor,
+            dismissInteractor = keyguardDismissInteractor,
+            applicationScope = testScope.backgroundScope,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
new file mode 100644
index 0000000..f33ca95
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.systemui.keyguard.domain.interactor
+
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.keyguard.data.repository.trustRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.user.domain.interactor.selectedUserInteractor
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.keyguardDismissInteractor by
+    Kosmos.Fixture {
+        KeyguardDismissInteractor(
+            trustRepository = trustRepository,
+            keyguardRepository = keyguardRepository,
+            primaryBouncerInteractor = primaryBouncerInteractor,
+            alternateBouncerInteractor = alternateBouncerInteractor,
+            powerInteractor = powerInteractor,
+            selectedUserInteractor = selectedUserInteractor,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
index ffa4133..9774e4a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt
@@ -19,21 +19,19 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
-import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.keyguard.domain.interactor.keyguardDismissActionInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.sysuiStatusBarStateController
-import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 val Kosmos.bouncerToGoneFlows by Fixture {
     BouncerToGoneFlows(
         statusBarStateController = sysuiStatusBarStateController,
         primaryBouncerInteractor = mockPrimaryBouncerInteractor,
-        keyguardDismissActionInteractor = mock(),
-        featureFlags = featureFlagsClassic,
+        keyguardDismissActionInteractor = { keyguardDismissActionInteractor },
         shadeInteractor = shadeInteractor,
         animationFlow = keyguardTransitionAnimationFlow,
     )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt
index f86e9b7..e6651a4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt
@@ -20,8 +20,6 @@
 
 import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
@@ -32,7 +30,5 @@
         deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
         configurationInteractor = configurationInteractor,
         animationFlow = keyguardTransitionAnimationFlow,
-        keyguardInteractor = keyguardInteractor,
-        keyguardTransitionInteractor = keyguardTransitionInteractor,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
index 4ecff73..d6edea2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt
@@ -19,20 +19,18 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor
-import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.keyguard.domain.interactor.keyguardDismissActionInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.statusbar.sysuiStatusBarStateController
-import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture {
     PrimaryBouncerToGoneTransitionViewModel(
         statusBarStateController = sysuiStatusBarStateController,
         primaryBouncerInteractor = mockPrimaryBouncerInteractor,
-        keyguardDismissActionInteractor = mock(),
-        featureFlags = featureFlagsClassic,
+        keyguardDismissActionInteractor = { keyguardDismissActionInteractor },
         bouncerToGoneFlows = bouncerToGoneFlows,
         animationFlow = keyguardTransitionAnimationFlow,
     )
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 afc8f30..a46d358 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
@@ -48,6 +48,7 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.sceneContainerConfig
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import com.android.systemui.scene.shared.model.sceneDataSource
 import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
@@ -70,6 +71,7 @@
     val testScope by lazy { kosmos.testScope }
     val fakeFeatureFlags by lazy { kosmos.fakeFeatureFlagsClassic }
     val fakeSceneContainerFlags by lazy { kosmos.fakeSceneContainerFlags }
+    val sceneContainerFlags by lazy { kosmos.sceneContainerFlags }
     val fakeExecutor by lazy { kosmos.fakeExecutor }
     val fakeExecutorHandler by lazy { kosmos.fakeExecutorHandler }
     val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
index b66d7f9..d4a72b4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
@@ -24,8 +24,9 @@
 
     private val sliceByWidth = mutableMapOf<Int, MutableStateFlow<Slice?>>()
 
-    override fun ancSlice(width: Int): Flow<Slice?> =
-        sliceByWidth.getOrPut(width) { MutableStateFlow(null) }
+    override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
+        return sliceByWidth.getOrPut(width) { MutableStateFlow(null) }
+    }
 
     fun putSlice(width: Int, slice: Slice?) {
         sliceByWidth.getOrPut(width) { MutableStateFlow(null) }.value = slice
diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md
index 7c0cee8..2ab43bb 100644
--- a/ravenwood/test-authors.md
+++ b/ravenwood/test-authors.md
@@ -17,6 +17,7 @@
     name: "MyTestsRavenwood",
     static_libs: [
         "androidx.annotation_annotation",
+        "androidx.test.ext.junit",
         "androidx.test.rules",
     ],
     srcs: [
@@ -34,7 +35,7 @@
 import android.platform.test.annotations.IgnoreUnderRavenwood;
 import android.platform.test.ravenwood.RavenwoodRule;
 
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/Android.bp b/services/Android.bp
index 881d6e1..6235195 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -241,6 +241,7 @@
     libs: [
         "android.hidl.manager-V1.0-java",
         "framework-tethering.stubs.module_lib",
+        "keepanno-annotations",
         "service-art.stubs.system_server",
         "service-permission.stubs.system_server",
         "service-rkp.stubs.system_server",
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 1d6399e..bfa1c7b 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -49,6 +49,13 @@
 }
 
 flag {
+    name: "enable_a11y_checker_logging"
+    namespace: "accessibility"
+    description: "Whether to identify and log app a11y issues."
+    bug: "325420273"
+}
+
+flag {
     name: "enable_magnification_joystick"
     namespace: "accessibility"
     description: "Whether to enable joystick controls for magnification"
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index bbbc4ae..e64e500 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -4175,8 +4175,13 @@
     public void enableShortcutsForTargets(
             boolean enable, @UserShortcutType int shortcutTypes,
             @NonNull List<String> shortcutTargets, @UserIdInt int userId) {
-        mContext.enforceCallingPermission(
-                Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets");
+        if (android.view.accessibility.Flags.migrateEnableShortcuts()) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets");
+        } else {
+            mContext.enforceCallingPermission(
+                    Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets");
+        }
         for (int shortcutType : USER_SHORTCUT_TYPES) {
             if ((shortcutTypes & shortcutType) == shortcutType) {
                 enableShortcutForTargets(enable, shortcutType, shortcutTargets, userId);
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index 0a3906a..ced10fb 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -1,5 +1,4 @@
 package: "android.service.autofill"
-container: "system"
 
 flag {
   name: "test"
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index 1dc3b73..c130cee 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -1,5 +1,4 @@
 package: "android.service.autofill"
-container: "system"
 
 flag {
   name: "autofill_credman_integration"
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index f38d772b..23373f1 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -28,6 +28,7 @@
 import android.app.WindowConfiguration;
 import android.app.compat.CompatChanges;
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
+import android.companion.virtual.flags.Flags;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.AttributionSource;
@@ -298,14 +299,28 @@
     public boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
             @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
             int launchingFromDisplayId, boolean isNewTask) {
-        if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, isNewTask)) {
-            notifyActivityBlocked(activityInfo);
-            return false;
-        }
-        if (mIntentListenerCallback != null && intent != null
-                && mIntentListenerCallback.shouldInterceptIntent(intent)) {
-            Slog.d(TAG, "Virtual device intercepting intent");
-            return false;
+        if (Flags.interceptIntentsBeforeApplyingPolicy()) {
+            if (mIntentListenerCallback != null && intent != null
+                    && mIntentListenerCallback.shouldInterceptIntent(intent)) {
+                Slog.d(TAG, "Virtual device intercepting intent");
+                return false;
+            }
+            if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId,
+                    isNewTask)) {
+                notifyActivityBlocked(activityInfo);
+                return false;
+            }
+        } else {
+            if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId,
+                    isNewTask)) {
+                notifyActivityBlocked(activityInfo);
+                return false;
+            }
+            if (mIntentListenerCallback != null && intent != null
+                    && mIntentListenerCallback.shouldInterceptIntent(intent)) {
+                Slog.d(TAG, "Virtual device intercepting intent");
+                return false;
+            }
         }
         return true;
     }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index fd7e4ab..392c0c7 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -182,6 +182,7 @@
         "android.hardware.vibrator-V2-java",
         "app-compat-annotations",
         "framework-tethering.stubs.module_lib",
+        "keepanno-annotations",
         "service-art.stubs.system_server",
         "service-permission.stubs.system_server",
         "service-rkp.stubs.system_server",
@@ -213,7 +214,9 @@
         "android.hardware.health-V3-java", // AIDL
         "android.hardware.health-translate-java",
         "android.hardware.light-V1-java",
+        "android.hardware.security.authgraph-V1-java",
         "android.hardware.security.rkp-V3-java",
+        "android.hardware.security.secretkeeper-V1-java",
         "android.hardware.tv.cec-V1.1-java",
         "android.hardware.tv.hdmi.cec-V1-java",
         "android.hardware.tv.hdmi.connection-V1-java",
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index e7fae24..67e18ca 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -107,6 +107,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.DiskInfo;
+import android.os.storage.ICeStorageLockEventListener;
 import android.os.storage.IObbActionListener;
 import android.os.storage.IStorageEventListener;
 import android.os.storage.IStorageManager;
@@ -139,6 +140,7 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.AppFuseMount;
@@ -185,6 +187,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -602,6 +605,9 @@
     // Not guarded by lock, always used on the ActivityManager thread
     private final SparseArray<PackageMonitor> mPackageMonitorsForUser = new SparseArray<>();
 
+    /** List of listeners registered for ce storage callbacks */
+    private final CopyOnWriteArrayList<ICeStorageLockEventListener>
+            mCeStorageEventCallbacks = new CopyOnWriteArrayList<>();
 
     class ObbState implements IBinder.DeathRecipient {
         public ObbState(String rawPath, String canonicalPath, int callingUid,
@@ -3315,6 +3321,11 @@
         synchronized (mLock) {
             mCeUnlockedUsers.remove(userId);
         }
+        if (android.os.Flags.allowPrivateProfile()
+                && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
+            dispatchCeStorageLockedEvent(userId);
+        }
     }
 
     @Override
@@ -4580,6 +4591,18 @@
         return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
     }
 
+    @VisibleForTesting
+    CopyOnWriteArrayList<ICeStorageLockEventListener> getCeStorageEventCallbacks() {
+        return mCeStorageEventCallbacks;
+    }
+
+    @VisibleForTesting
+    void dispatchCeStorageLockedEvent(int userId) {
+        for (ICeStorageLockEventListener listener: mCeStorageEventCallbacks) {
+            listener.onStorageLocked(userId);
+        }
+    }
+
     private static class Callbacks extends Handler {
         private static final int MSG_STORAGE_STATE_CHANGED = 1;
         private static final int MSG_VOLUME_STATE_CHANGED = 2;
@@ -5066,5 +5089,23 @@
                 throw new IOException(e);
             }
         }
+
+        @Override
+        public void registerStorageLockEventListener(
+                @NonNull ICeStorageLockEventListener listener) {
+            boolean registered = mCeStorageEventCallbacks.add(listener);
+            if (!registered) {
+                Slog.w(TAG, "Failed to register listener: " + listener);
+            }
+        }
+
+        @Override
+        public void unregisterStorageLockEventListener(
+                @NonNull ICeStorageLockEventListener listener) {
+            boolean unregistered = mCeStorageEventCallbacks.remove(listener);
+            if (!unregistered) {
+                Slog.w(TAG, "Unregistering " + listener + " that was not registered");
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index baae40b..5933639 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -74,6 +74,15 @@
             "file_patterns": ["SensitiveContentProtectionManagerService\\.java"]
         },
         {
+            "name": "FrameworksMockingServicesTests",
+            "options": [
+                {
+                    "include-filter": "com.android.server.StorageManagerServiceTest"
+                }
+            ],
+            "file_patterns": ["StorageManagerService\\.java"]
+        },
+        {
             "name": "FrameworksServicesTests",
             "options": [
                 {
diff --git a/services/core/java/com/android/server/app/flags.aconfig b/services/core/java/com/android/server/app/flags.aconfig
index 54e4571..0673013 100644
--- a/services/core/java/com/android/server/app/flags.aconfig
+++ b/services/core/java/com/android/server/app/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.server.app"
-container: "system"
 
 flag {
     name: "game_default_frame_rate"
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5ba0af4..9896d9d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5464,19 +5464,19 @@
 
     /** @see AudioManager#setMicrophoneMuteFromSwitch(boolean) */
     public void setMicrophoneMuteFromSwitch(boolean on) {
-        int userId = Binder.getCallingUid();
-        if (userId != android.os.Process.SYSTEM_UID) {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid != android.os.Process.SYSTEM_UID) {
             Log.e(TAG, "setMicrophoneMuteFromSwitch() called from non system user!");
             return;
         }
         mMicMuteFromSwitch = on;
         new MediaMetrics.Item(MediaMetrics.Name.AUDIO_MIC)
-                .setUid(userId)
+                .setUid(callingUid)
                 .set(MediaMetrics.Property.EVENT, "setMicrophoneMuteFromSwitch")
                 .set(MediaMetrics.Property.REQUEST, on
                         ? MediaMetrics.Value.MUTE : MediaMetrics.Value.UNMUTE)
                 .record();
-        setMicrophoneMuteNoCallerCheck(userId);
+        setMicrophoneMuteNoCallerCheck(UserHandle.getCallingUserId());
     }
 
     private void setMicMuteFromSwitchInput() {
@@ -5507,9 +5507,10 @@
         if (DEBUG_VOL) {
             Log.d(TAG, String.format("Mic mute %b, user=%d", muted, userId));
         }
-        // only mute for the current user
-        if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) {
+        // only mute for the current user or for the system user.
+        if (getCurrentUserId() == userId || userId == UserHandle.USER_SYSTEM) {
             final boolean currentMute = mAudioSystem.isMicrophoneMuted();
+            int callingUid = Binder.getCallingUid();
             final long identity = Binder.clearCallingIdentity();
             try {
                 final int ret = mAudioSystem.muteMicrophone(muted);
@@ -5522,7 +5523,7 @@
                 }
 
                 new MediaMetrics.Item(MediaMetrics.Name.AUDIO_MIC)
-                        .setUid(userId)
+                        .setUid(callingUid)
                         .set(MediaMetrics.Property.EVENT, "setMicrophoneMuteNoCallerCheck")
                         .set(MediaMetrics.Property.MUTE, mMicMuteFromSystemCached
                                 ? MediaMetrics.Value.ON : MediaMetrics.Value.OFF)
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index 5b9469b..1ea72d7 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -34,10 +34,11 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
-import com.google.android.collect.Sets;
 
 import com.android.server.backup.Flags;
 
+import com.google.android.collect.Sets;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.Set;
@@ -64,6 +65,7 @@
     private static final String APP_LOCALES_HELPER = "app_locales";
     private static final String APP_GENDER_HELPER = "app_gender";
     private static final String COMPANION_HELPER = "companion";
+    private static final String SYSTEM_GENDER_HELPER = "system_gender";
 
     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
     // are also used in the full-backup file format, so must not change unless steps are
@@ -99,7 +101,9 @@
                     NOTIFICATION_HELPER,
                     SYNC_SETTINGS_HELPER,
                     APP_LOCALES_HELPER,
-                    COMPANION_HELPER);
+                    COMPANION_HELPER,
+                    APP_GENDER_HELPER,
+                    SYSTEM_GENDER_HELPER);
 
     /** Helpers that are enabled for full, non-system users. */
     private static final Set<String> sEligibleHelpersForNonSystemUser =
@@ -139,6 +143,8 @@
         addHelperIfEligibleForUser(APP_GENDER_HELPER,
                 new AppGrammaticalGenderBackupHelper(mUserId));
         addHelperIfEligibleForUser(COMPANION_HELPER, new CompanionBackupHelper(mUserId));
+        addHelperIfEligibleForUser(SYSTEM_GENDER_HELPER,
+                new SystemGrammaticalGenderBackupHelper(mUserId));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/backup/SystemGrammaticalGenderBackupHelper.java b/services/core/java/com/android/server/backup/SystemGrammaticalGenderBackupHelper.java
new file mode 100644
index 0000000..c0d398e
--- /dev/null
+++ b/services/core/java/com/android/server/backup/SystemGrammaticalGenderBackupHelper.java
@@ -0,0 +1,66 @@
+/*
+ * 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.server.backup;
+
+import static android.app.backup.BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
+
+import android.annotation.UserIdInt;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BlobBackupHelper;
+import android.os.ParcelFileDescriptor;
+
+import com.android.server.LocalServices;
+import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
+
+public class SystemGrammaticalGenderBackupHelper extends BlobBackupHelper {
+    private static final int BLOB_VERSION = 1;
+    private static final String KEY_SYSTEM_GENDER = "system_gender";
+
+    private final @UserIdInt int mUserId;
+    private final GrammaticalInflectionManagerInternal mGrammarInflectionManagerInternal;
+
+    public SystemGrammaticalGenderBackupHelper(int userId) {
+        super(BLOB_VERSION, KEY_SYSTEM_GENDER);
+        mUserId = userId;
+        mGrammarInflectionManagerInternal = LocalServices.getService(
+                GrammaticalInflectionManagerInternal.class);
+    }
+
+    @Override
+    public void performBackup(ParcelFileDescriptor oldStateFd, BackupDataOutput data,
+            ParcelFileDescriptor newStateFd) {
+        // Only backup the gender data if e2e encryption is present
+        if ((data.getTransportFlags() & FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED) == 0) {
+            return;
+        }
+
+        super.performBackup(oldStateFd, data, newStateFd);
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        return KEY_SYSTEM_GENDER.equals(key) && mGrammarInflectionManagerInternal != null
+                ? mGrammarInflectionManagerInternal.getSystemBackupPayload(mUserId) : null;
+    }
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload) {
+        if (KEY_SYSTEM_GENDER.equals(key) && mGrammarInflectionManagerInternal != null) {
+            mGrammarInflectionManagerInternal.applyRestoredSystemPayload(payload, mUserId);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index f51b62d..4af30a9 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -89,11 +89,23 @@
         return true;
     }
 
-    /** If virtualized biometrics are supported (requires debug build). */
-    public static boolean isVirtualEnabled(@NonNull Context context) {
+    /** If virtualized fingerprint sensor is supported. */
+    public static boolean isFingerprintVirtualEnabled(@NonNull Context context) {
         return Build.isDebuggable()
-                && Settings.Secure.getIntForUser(context.getContentResolver(),
-                Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
+                && (Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.BIOMETRIC_FINGERPRINT_VIRTUAL_ENABLED, 0,
+                UserHandle.USER_CURRENT) == 1
+                || Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 0, UserHandle.USER_CURRENT) == 1);
+    }
+
+    /** If virtualized face sensor is supported. */
+    public static boolean isFaceVirtualEnabled(@NonNull Context context) {
+        return Build.isDebuggable()
+                && (Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.BIOMETRIC_FACE_VIRTUAL_ENABLED, 0, UserHandle.USER_CURRENT) == 1
+                || Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 0, UserHandle.USER_CURRENT) == 1);
     }
 
     /**
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 1037124..a946af8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -748,7 +748,7 @@
             final String virtualInstance = "virtual";
             final boolean isVirtualHalPresent =
                     faceSensorConfigurations.doesInstanceExist(virtualInstance);
-            if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
+            if (Flags.faceVhalFeature() && Utils.isFaceVirtualEnabled(getContext())) {
                 if (isVirtualHalPresent) {
                     return new Pair<>(virtualInstance,
                             faceSensorConfigurations.getSensorPropForInstance(virtualInstance));
@@ -786,7 +786,7 @@
             }
 
             final int virtualAt = aidlInstances.indexOf("virtual");
-            if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
+            if (Flags.faceVhalFeature() && Utils.isFaceVirtualEnabled(getContext())) {
                 if (virtualAt != -1) {
                     //only virtual instance should be returned
                     Slog.i(TAG, "virtual hal is used");
@@ -928,7 +928,7 @@
 
     void syncEnrollmentsNow() {
         Utils.checkPermissionOrShell(getContext(), MANAGE_FACE);
-        if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
+        if (Flags.faceVhalFeature() && Utils.isFaceVirtualEnabled(getContext())) {
             Slog.i(TAG, "Sync virtual enrollments");
             final int userId = ActivityManager.getCurrentUser();
             for (ServiceProvider provider : mRegistry.getProviders()) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 2dc03ed..d762914 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -1136,7 +1136,7 @@
         final String virtualInstance = "virtual";
         final boolean isVirtualHalPresent =
                 fingerprintSensorConfigurations.doesInstanceExist(virtualInstance);
-        if (Utils.isVirtualEnabled(getContext())) {
+        if (Utils.isFingerprintVirtualEnabled(getContext())) {
             if (isVirtualHalPresent) {
                 return new Pair<>(virtualInstance,
                         fingerprintSensorConfigurations.getSensorPropForInstance(virtualInstance));
@@ -1169,7 +1169,7 @@
         }
 
         final int virtualAt = aidlInstances.indexOf("virtual");
-        if (Utils.isVirtualEnabled(getContext())) {
+        if (Utils.isFingerprintVirtualEnabled(getContext())) {
             if (virtualAt != -1) {
                 //only virtual instance should be returned
                 Slog.i(TAG, "virtual hal is used");
@@ -1295,7 +1295,7 @@
 
     void syncEnrollmentsNow() {
         Utils.checkPermissionOrShell(getContext(), MANAGE_FINGERPRINT);
-        if (Utils.isVirtualEnabled(getContext())) {
+        if (Utils.isFingerprintVirtualEnabled(getContext())) {
             Slog.i(TAG, "Sync virtual enrollments");
             final int userId = ActivityManager.getCurrentUser();
             final CountDownLatch latch = new CountDownLatch(mRegistry.getProviders().size());
@@ -1324,7 +1324,7 @@
     }
 
     void simulateVhalFingerDown() {
-        if (Utils.isVirtualEnabled(getContext())) {
+        if (Utils.isFingerprintVirtualEnabled(getContext())) {
             Slog.i(TAG, "Simulate virtual HAL finger down event");
             final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
             if (provider != null) {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 06dc7f5..9c020a7 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -425,7 +425,7 @@
         return mScreenAutoBrightness;
     }
 
-    float getRawAutomaticScreenBrightness() {
+    public float getRawAutomaticScreenBrightness() {
         return mRawScreenAutoBrightness;
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java
index d50a43a..e3e3be2 100644
--- a/services/core/java/com/android/server/display/DisplayBrightnessState.java
+++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java
@@ -18,6 +18,7 @@
 
 import android.text.TextUtils;
 
+import com.android.server.display.brightness.BrightnessEvent;
 import com.android.server.display.brightness.BrightnessReason;
 
 import java.util.Objects;
@@ -43,6 +44,8 @@
 
     private final float mCustomAnimationRate;
 
+    private final BrightnessEvent mBrightnessEvent;
+
     private DisplayBrightnessState(Builder builder) {
         mBrightness = builder.getBrightness();
         mSdrBrightness = builder.getSdrBrightness();
@@ -54,6 +57,7 @@
         mMinBrightness = builder.getMinBrightness();
         mCustomAnimationRate = builder.getCustomAnimationRate();
         mShouldUpdateScreenBrightnessSetting = builder.shouldUpdateScreenBrightnessSetting();
+        mBrightnessEvent = builder.getBrightnessEvent();
     }
 
     /**
@@ -127,6 +131,13 @@
         return mShouldUpdateScreenBrightnessSetting;
     }
 
+    /**
+     * @return The BrightnessEvent object
+     */
+    public BrightnessEvent getBrightnessEvent() {
+        return mBrightnessEvent;
+    }
+
     @Override
     public String toString() {
         StringBuilder stringBuilder = new StringBuilder("DisplayBrightnessState:");
@@ -144,6 +155,8 @@
         stringBuilder.append("\n    customAnimationRate:").append(mCustomAnimationRate);
         stringBuilder.append("\n    shouldUpdateScreenBrightnessSetting:")
                 .append(mShouldUpdateScreenBrightnessSetting);
+        stringBuilder.append("\n    mBrightnessEvent:")
+                .append(Objects.toString(mBrightnessEvent, "null"));
         return stringBuilder.toString();
     }
 
@@ -173,7 +186,8 @@
                 && mMinBrightness == otherState.getMinBrightness()
                 && mCustomAnimationRate == otherState.getCustomAnimationRate()
                 && mShouldUpdateScreenBrightnessSetting
-                    == otherState.shouldUpdateScreenBrightnessSetting();
+                    == otherState.shouldUpdateScreenBrightnessSetting()
+                && Objects.equals(mBrightnessEvent, otherState.getBrightnessEvent());
     }
 
     @Override
@@ -181,7 +195,7 @@
         return Objects.hash(mBrightness, mSdrBrightness, mBrightnessReason,
                 mShouldUseAutoBrightness, mIsSlowChange, mMaxBrightness, mMinBrightness,
                 mCustomAnimationRate,
-                mShouldUpdateScreenBrightnessSetting);
+                mShouldUpdateScreenBrightnessSetting, mBrightnessEvent);
     }
 
     /**
@@ -206,6 +220,8 @@
         private float mCustomAnimationRate = CUSTOM_ANIMATION_RATE_NOT_SET;
         private boolean mShouldUpdateScreenBrightnessSetting;
 
+        private BrightnessEvent mBrightnessEvent;
+
         /**
          * Create a builder starting with the values from the specified {@link
          * DisplayBrightnessState}.
@@ -225,6 +241,7 @@
             builder.setCustomAnimationRate(state.getCustomAnimationRate());
             builder.setShouldUpdateScreenBrightnessSetting(
                     state.shouldUpdateScreenBrightnessSetting());
+            builder.setBrightnessEvent(state.getBrightnessEvent());
             return builder;
         }
 
@@ -400,5 +417,22 @@
         public DisplayBrightnessState build() {
             return new DisplayBrightnessState(this);
         }
+
+
+        /**
+         * This is used to get the BrightnessEvent object from its builder
+         */
+        public BrightnessEvent getBrightnessEvent() {
+            return mBrightnessEvent;
+        }
+
+
+        /**
+         * This is used to set the BrightnessEvent object
+         */
+        public Builder setBrightnessEvent(BrightnessEvent brightnessEvent) {
+            mBrightnessEvent = brightnessEvent;
+            return this;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 404c3ad..cfdb75f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -83,7 +83,7 @@
 import com.android.server.display.brightness.BrightnessUtils;
 import com.android.server.display.brightness.DisplayBrightnessController;
 import com.android.server.display.brightness.clamper.BrightnessClamperController;
-import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
+import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2;
 import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
 import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
 import com.android.server.display.config.HysteresisLevels;
@@ -440,7 +440,7 @@
 
     // Responsible for evaluating and tracking the automatic brightness relevant states.
     // Todo: This is a temporary workaround. Ideally DPC2 should never talk to the strategies
-    private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy;
+    private final AutomaticBrightnessStrategy2 mAutomaticBrightnessStrategy;
 
     // A record of state for skipping brightness ramps.
     private int mSkipRampState = RAMP_STATE_SKIP_NONE;
@@ -1337,9 +1337,6 @@
                     ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
         }
 
-        final boolean userSetBrightnessChanged = mDisplayBrightnessController
-                .updateUserSetScreenBrightness();
-
         DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController
                 .updateBrightness(mPowerRequest, state);
         float brightnessState = displayBrightnessState.getBrightness();
@@ -1348,7 +1345,11 @@
         boolean slowChange = displayBrightnessState.isSlowChange();
         // custom transition duration
         float customAnimationRate = displayBrightnessState.getCustomAnimationRate();
-
+        final boolean userSetBrightnessChanged =
+                mDisplayBrightnessController.getIsUserSetScreenBrightnessUpdated();
+        if (displayBrightnessState.getBrightnessEvent() != null) {
+            mTempBrightnessEvent.copyFrom(displayBrightnessState.getBrightnessEvent());
+        }
         // Set up the ScreenOff controller used when coming out of SCREEN_OFF and the ALS sensor
         // doesn't yet have a valid lux value to use with auto-brightness.
         if (mScreenOffBrightnessSensorController != null) {
@@ -1364,11 +1365,13 @@
         // request changes.
         final boolean wasShortTermModelActive =
                 mAutomaticBrightnessStrategy.isShortTermModelActive();
-        mAutomaticBrightnessStrategy.setAutoBrightnessState(state,
-                mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(),
-                mBrightnessReasonTemp.getReason(), mPowerRequest.policy,
-                mDisplayBrightnessController.getLastUserSetScreenBrightness(),
-                userSetBrightnessChanged);
+        if (!mFlags.isRefactorDisplayPowerControllerEnabled()) {
+            mAutomaticBrightnessStrategy.setAutoBrightnessState(state,
+                    mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(),
+                    mBrightnessReasonTemp.getReason(), mPowerRequest.policy,
+                    mDisplayBrightnessController.getLastUserSetScreenBrightness(),
+                    userSetBrightnessChanged);
+        }
 
         // If the brightness is already set then it's been overridden by something other than the
         // user, or is a temporary adjustment.
@@ -1390,9 +1393,22 @@
         float currentBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness();
         // Apply auto-brightness.
         int brightnessAdjustmentFlags = 0;
+        // All the conditions inside this if block will be moved to AutomaticBrightnessStrategy
+        if (mFlags.isRefactorDisplayPowerControllerEnabled()
+                && displayBrightnessState.getBrightnessReason().getReason()
+                        == BrightnessReason.REASON_AUTOMATIC) {
+            brightnessAdjustmentFlags =
+                    mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags();
+            updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
+            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
+            if (mScreenOffBrightnessSensorController != null) {
+                mScreenOffBrightnessSensorController.setLightSensorEnabled(false);
+            }
+            setBrightnessFromOffload(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        }
         // AutomaticBrightnessStrategy has higher priority than OffloadBrightnessStrategy
-        if (Float.isNaN(brightnessState)
-                || mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_OFFLOAD) {
+        if (!mFlags.isRefactorDisplayPowerControllerEnabled() && (Float.isNaN(brightnessState)
+                || mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_OFFLOAD)) {
             if (mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()) {
                 brightnessState = mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
                         mTempBrightnessEvent);
@@ -1422,8 +1438,8 @@
             }
         } else {
             // Any non-auto-brightness values such as override or temporary should still be subject
-            // to clamping so that they don't go beyond the current max as specified by HBM
-            // Controller.
+            // to clamping so that they don't go beyond the current max as specified by Brightness
+            // Range Controller.
             brightnessState = clampScreenBrightness(brightnessState);
             mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false);
         }
diff --git a/services/core/java/com/android/server/display/ExternalDisplayPolicy.java b/services/core/java/com/android/server/display/ExternalDisplayPolicy.java
index a12d248..b24caf4 100644
--- a/services/core/java/com/android/server/display/ExternalDisplayPolicy.java
+++ b/services/core/java/com/android/server/display/ExternalDisplayPolicy.java
@@ -222,7 +222,7 @@
         } else {
             // As external display is enabled by default, need to disable it now.
             // TODO(b/292196201) Remove when the display can be disabled before DPC is created.
-            logicalDisplay.setEnabledLocked(false);
+            mLogicalDisplayMapper.setDisplayEnabledLocked(logicalDisplay, false);
         }
 
         if (!isExternalDisplayAllowed()) {
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 8084685..8b3e4a4 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -31,7 +31,7 @@
 import com.android.server.display.BrightnessMappingStrategy;
 import com.android.server.display.BrightnessSetting;
 import com.android.server.display.DisplayBrightnessState;
-import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
+import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2;
 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
 import com.android.server.display.feature.DisplayManagerFlags;
 
@@ -76,6 +76,10 @@
     @GuardedBy("mLock")
     private float mLastUserSetScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
 
+    // Represents if the system has adjusted the brightness based on the user suggested value. Will
+    // be false if the brightness change is coming from a non-user source
+    private boolean mUserSetScreenBrightnessUpdated;
+
     // The listener which is to be notified everytime there is a change in the brightness in the
     // BrightnessSetting.
     private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener;
@@ -138,7 +142,6 @@
     public DisplayBrightnessState updateBrightness(
             DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
             int targetDisplayState) {
-
         DisplayBrightnessState state;
         synchronized (mLock) {
             mDisplayBrightnessStrategy = mDisplayBrightnessStrategySelector.selectStrategy(
@@ -246,28 +249,14 @@
     }
 
     /**
-     * We want to return true if the user has set the screen brightness.
-     * RBC on, off, and intensity changes will return false.
-     * Slider interactions whilst in RBC will return true, just as when in non-rbc.
+     * Returns if the system has adjusted the brightness based on the user suggested value. Will
+     * be false if the brightness change is coming from a non-user source.
+     *
+     * Todo: 294444204 This is a temporary workaround, and should be moved to the manual brightness
+     * strategy once that is introduced
      */
-    public boolean updateUserSetScreenBrightness() {
-        synchronized (mLock) {
-            if (!BrightnessUtils.isValidBrightnessValue(mPendingScreenBrightness)) {
-                return false;
-            }
-            if (mCurrentScreenBrightness == mPendingScreenBrightness) {
-                mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-                setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT);
-                return false;
-            }
-            setCurrentScreenBrightnessLocked(mPendingScreenBrightness);
-            mLastUserSetScreenBrightness = mPendingScreenBrightness;
-            mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-            setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT);
-        }
-        notifyCurrentScreenBrightness();
-        return true;
-
+    public boolean getIsUserSetScreenBrightnessUpdated() {
+        return mUserSetScreenBrightnessUpdated;
     }
 
     /**
@@ -355,7 +344,7 @@
     /**
      * TODO(b/253226419): Remove once auto-brightness is a fully-functioning strategy.
      */
-    public AutomaticBrightnessStrategy getAutomaticBrightnessStrategy() {
+    public AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy() {
         return mDisplayBrightnessStrategySelector.getAutomaticBrightnessStrategy();
     }
 
@@ -442,6 +431,33 @@
         }
     }
 
+    /**
+     * We want to return true if the user has set the screen brightness.
+     * RBC on, off, and intensity changes will return false.
+     * Slider interactions whilst in RBC will return true, just as when in non-rbc.
+     */
+    @VisibleForTesting
+    boolean updateUserSetScreenBrightness() {
+        mUserSetScreenBrightnessUpdated = false;
+        synchronized (mLock) {
+            if (!BrightnessUtils.isValidBrightnessValue(mPendingScreenBrightness)) {
+                return false;
+            }
+            if (mCurrentScreenBrightness == mPendingScreenBrightness) {
+                mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+                setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+                return false;
+            }
+            setCurrentScreenBrightnessLocked(mPendingScreenBrightness);
+            mLastUserSetScreenBrightness = mPendingScreenBrightness;
+            mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        }
+        notifyCurrentScreenBrightness();
+        mUserSetScreenBrightnessUpdated = true;
+        return true;
+    }
+
     @VisibleForTesting
     static class Injector {
         DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector(Context context,
@@ -470,7 +486,7 @@
      * TODO(b/253226419): Remove once auto-brightness is a fully-functioning strategy.
      */
     private DisplayBrightnessState addAutomaticBrightnessState(DisplayBrightnessState state) {
-        AutomaticBrightnessStrategy autoStrat = getAutomaticBrightnessStrategy();
+        AutomaticBrightnessStrategy2 autoStrat = getAutomaticBrightnessStrategy();
 
         DisplayBrightnessState.Builder builder = DisplayBrightnessState.Builder.from(state);
         builder.setShouldUseAutoBrightness(
@@ -526,6 +542,12 @@
     private StrategySelectionRequest constructStrategySelectionRequest(
             DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
             int targetDisplayState) {
-        return new StrategySelectionRequest(displayPowerRequest, targetDisplayState);
+        boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
+        float lastUserSetScreenBrightness;
+        synchronized (mLock) {
+            lastUserSetScreenBrightness = mLastUserSetScreenBrightness;
+        }
+        return new StrategySelectionRequest(displayPowerRequest, targetDisplayState,
+                lastUserSetScreenBrightness, userSetBrightnessChanged);
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 165c24b..da66879 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -27,6 +27,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
+import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2;
 import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
@@ -65,7 +66,16 @@
     // The brightness strategy used to manage the brightness state when the request is invalid.
     private final InvalidBrightnessStrategy mInvalidBrightnessStrategy;
     // Controls brightness when automatic (adaptive) brightness is running.
-    private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy;
+    private final AutomaticBrightnessStrategy2 mAutomaticBrightnessStrategy;
+
+    // The automatic strategy which controls the brightness when adaptive mode is ON.
+    private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy1;
+
+    // The deprecated AutomaticBrightnessStrategy. Avoid using it for any new features without
+    // consulting with the display frameworks team. Use {@link AutomaticBrightnessStrategy} instead.
+    // This will be removed once the flag
+    // {@link DisplayManagerFlags#isRefactorDisplayPowerControllerEnabled is fully rolled out
+    private final AutomaticBrightnessStrategy2 mAutomaticBrightnessStrategy2;
     // Controls the brightness if adaptive brightness is on and there exists an active offload
     // session. Brightness value is provided by the offload session.
     @Nullable
@@ -101,7 +111,15 @@
         mBoostBrightnessStrategy = injector.getBoostBrightnessStrategy();
         mFollowerBrightnessStrategy = injector.getFollowerBrightnessStrategy(displayId);
         mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
-        mAutomaticBrightnessStrategy = injector.getAutomaticBrightnessStrategy(context, displayId);
+        mAutomaticBrightnessStrategy1 =
+                (!mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
+                        : injector.getAutomaticBrightnessStrategy1(context, displayId);
+        mAutomaticBrightnessStrategy2 =
+                (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
+                        : injector.getAutomaticBrightnessStrategy2(context, displayId);
+        mAutomaticBrightnessStrategy =
+                (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled())
+                        ? mAutomaticBrightnessStrategy1 : mAutomaticBrightnessStrategy2;
         if (flags.isDisplayOffloadEnabled()) {
             mOffloadBrightnessStrategy = injector.getOffloadBrightnessStrategy();
         } else {
@@ -110,7 +128,7 @@
         mDisplayBrightnessStrategies = new DisplayBrightnessStrategy[]{mInvalidBrightnessStrategy,
                 mScreenOffBrightnessStrategy, mDozeBrightnessStrategy, mFollowerBrightnessStrategy,
                 mBoostBrightnessStrategy, mOverrideBrightnessStrategy, mTemporaryBrightnessStrategy,
-                mOffloadBrightnessStrategy};
+                mAutomaticBrightnessStrategy1, mOffloadBrightnessStrategy};
         mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
                 R.bool.config_allowAutoBrightnessWhileDozing);
         mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName();
@@ -142,6 +160,9 @@
         } else if (BrightnessUtils.isValidBrightnessValue(
                 mTemporaryBrightnessStrategy.getTemporaryScreenBrightness())) {
             displayBrightnessStrategy = mTemporaryBrightnessStrategy;
+        } else if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()
+                && isAutomaticBrightnessStrategyValid(strategySelectionRequest)) {
+            displayBrightnessStrategy = mAutomaticBrightnessStrategy1;
         } else if (mAutomaticBrightnessStrategy.shouldUseAutoBrightness()
                 && mOffloadBrightnessStrategy != null && BrightnessUtils.isValidBrightnessValue(
                 mOffloadBrightnessStrategy.getOffloadScreenBrightness())) {
@@ -149,7 +170,8 @@
         }
 
         if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) {
-            postProcess(constructStrategySelectionNotifyRequest(displayBrightnessStrategy));
+            postProcess(constructStrategySelectionNotifyRequest(displayBrightnessStrategy,
+                    strategySelectionRequest));
         }
 
         if (!mOldBrightnessStrategyName.equals(displayBrightnessStrategy.getName())) {
@@ -170,7 +192,7 @@
         return mFollowerBrightnessStrategy;
     }
 
-    public AutomaticBrightnessStrategy getAutomaticBrightnessStrategy() {
+    public AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy() {
         return mAutomaticBrightnessStrategy;
     }
 
@@ -206,9 +228,28 @@
         }
     }
 
+    private boolean isAutomaticBrightnessStrategyValid(
+            StrategySelectionRequest strategySelectionRequest) {
+        mAutomaticBrightnessStrategy1.setAutoBrightnessState(
+                strategySelectionRequest.getTargetDisplayState(),
+                mAllowAutoBrightnessWhileDozingConfig,
+                BrightnessReason.REASON_UNKNOWN,
+                strategySelectionRequest.getDisplayPowerRequest().policy,
+                strategySelectionRequest.getLastUserSetScreenBrightness(),
+                strategySelectionRequest.isUserSetBrightnessChanged());
+        return mAutomaticBrightnessStrategy1.isAutoBrightnessValid();
+    }
+
     private StrategySelectionNotifyRequest constructStrategySelectionNotifyRequest(
-            DisplayBrightnessStrategy selectedDisplayBrightnessStrategy) {
-        return new StrategySelectionNotifyRequest(selectedDisplayBrightnessStrategy);
+            DisplayBrightnessStrategy selectedDisplayBrightnessStrategy,
+            StrategySelectionRequest strategySelectionRequest) {
+        return new StrategySelectionNotifyRequest(
+                        strategySelectionRequest.getDisplayPowerRequest(),
+                strategySelectionRequest.getTargetDisplayState(),
+                selectedDisplayBrightnessStrategy,
+                strategySelectionRequest.getLastUserSetScreenBrightness(),
+                strategySelectionRequest.isUserSetBrightnessChanged(),
+                isAllowAutoBrightnessWhileDozingConfig());
     }
 
     private void postProcess(StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
@@ -263,10 +304,16 @@
             return new InvalidBrightnessStrategy();
         }
 
-        AutomaticBrightnessStrategy getAutomaticBrightnessStrategy(Context context, int displayId) {
+        AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context,
+                int displayId) {
             return new AutomaticBrightnessStrategy(context, displayId);
         }
 
+        AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy2(Context context,
+                int displayId) {
+            return new AutomaticBrightnessStrategy2(context, displayId);
+        }
+
         OffloadBrightnessStrategy getOffloadBrightnessStrategy() {
             return new OffloadBrightnessStrategy();
         }
diff --git a/services/core/java/com/android/server/display/brightness/StrategySelectionNotifyRequest.java b/services/core/java/com/android/server/display/brightness/StrategySelectionNotifyRequest.java
index d8bd2e4..6e6c972 100644
--- a/services/core/java/com/android/server/display/brightness/StrategySelectionNotifyRequest.java
+++ b/services/core/java/com/android/server/display/brightness/StrategySelectionNotifyRequest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display.brightness;
 
+import android.hardware.display.DisplayManagerInternal;
+
 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
 
 import java.util.Objects;
@@ -25,11 +27,36 @@
  * DisplayBrightnessStrategy
  */
 public final class StrategySelectionNotifyRequest {
+    // The request to change the associated display's state and brightness
+    private DisplayManagerInternal.DisplayPowerRequest mDisplayPowerRequest;
+
+    // The display state to which the screen is switching to
+    private int mTargetDisplayState;
+
     // The strategy that was selected with the current request
     private final DisplayBrightnessStrategy mSelectedDisplayBrightnessStrategy;
 
-    public StrategySelectionNotifyRequest(DisplayBrightnessStrategy displayBrightnessStrategy) {
+    // The last brightness that was set by the user and not temporary. Set to
+    // PowerManager.BRIGHTNESS_INVALID_FLOAT when a brightness has yet to be recorded.
+    private float mLastUserSetScreenBrightness;
+
+    // Represents if the user set screen brightness was changed or not.
+    private boolean mUserSetBrightnessChanged;
+
+    // True if light sensor is to be used to automatically determine doze screen brightness.
+    private final boolean mAllowAutoBrightnessWhileDozingConfig;
+
+    public StrategySelectionNotifyRequest(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, int targetDisplayState,
+            DisplayBrightnessStrategy displayBrightnessStrategy,
+            float lastUserSetScreenBrightness,
+            boolean userSetBrightnessChanged, boolean allowAutoBrightnessWhileDozingConfig) {
+        mDisplayPowerRequest = displayPowerRequest;
+        mTargetDisplayState = targetDisplayState;
         mSelectedDisplayBrightnessStrategy = displayBrightnessStrategy;
+        mLastUserSetScreenBrightness = lastUserSetScreenBrightness;
+        mUserSetBrightnessChanged = userSetBrightnessChanged;
+        mAllowAutoBrightnessWhileDozingConfig = allowAutoBrightnessWhileDozingConfig;
     }
 
     public DisplayBrightnessStrategy getSelectedDisplayBrightnessStrategy() {
@@ -43,11 +70,52 @@
         }
         StrategySelectionNotifyRequest other = (StrategySelectionNotifyRequest) obj;
         return other.getSelectedDisplayBrightnessStrategy()
-                == getSelectedDisplayBrightnessStrategy();
+                == getSelectedDisplayBrightnessStrategy()
+                && Objects.equals(mDisplayPowerRequest, other.getDisplayPowerRequest())
+                && mTargetDisplayState == other.getTargetDisplayState()
+                && mUserSetBrightnessChanged == other.isUserSetBrightnessChanged()
+                && mLastUserSetScreenBrightness == other.getLastUserSetScreenBrightness()
+                && mAllowAutoBrightnessWhileDozingConfig
+                == other.isAllowAutoBrightnessWhileDozingConfig();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSelectedDisplayBrightnessStrategy);
+        return Objects.hash(mSelectedDisplayBrightnessStrategy, mDisplayPowerRequest,
+                mTargetDisplayState, mUserSetBrightnessChanged, mLastUserSetScreenBrightness,
+                mAllowAutoBrightnessWhileDozingConfig);
+    }
+
+    public float getLastUserSetScreenBrightness() {
+        return mLastUserSetScreenBrightness;
+    }
+
+    public boolean isUserSetBrightnessChanged() {
+        return mUserSetBrightnessChanged;
+    }
+
+    public DisplayManagerInternal.DisplayPowerRequest getDisplayPowerRequest() {
+        return mDisplayPowerRequest;
+    }
+
+    public int getTargetDisplayState() {
+        return mTargetDisplayState;
+    }
+
+    public boolean isAllowAutoBrightnessWhileDozingConfig() {
+        return mAllowAutoBrightnessWhileDozingConfig;
+    }
+
+    /**
+     * A utility to stringify a StrategySelectionNotifyRequest
+     */
+    public String toString() {
+        return "StrategySelectionNotifyRequest:"
+                + " mDisplayPowerRequest=" + mDisplayPowerRequest
+                + " mTargetDisplayState=" + mTargetDisplayState
+                + " mSelectedDisplayBrightnessStrategy=" + mSelectedDisplayBrightnessStrategy
+                + " mLastUserSetScreenBrightness=" + mLastUserSetScreenBrightness
+                + " mUserSetBrightnessChanged=" + mUserSetBrightnessChanged
+                + " mAllowAutoBrightnessWhileDozingConfig=" + mAllowAutoBrightnessWhileDozingConfig;
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java b/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java
index e618596..ae745efc 100644
--- a/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java
+++ b/services/core/java/com/android/server/display/brightness/StrategySelectionRequest.java
@@ -31,10 +31,20 @@
     // The display state to which the screen is switching to
     private int mTargetDisplayState;
 
+    // The last brightness that was set by the user and not temporary. Set to
+    // PowerManager.BRIGHTNESS_INVALID_FLOAT when a brightness has yet to be recorded.
+    private float mLastUserSetScreenBrightness;
+
+    // Represents if the user set screen brightness was changed or not.
+    private boolean mUserSetBrightnessChanged;
+
     public StrategySelectionRequest(DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
-            int targetDisplayState) {
+            int targetDisplayState, float lastUserSetScreenBrightness,
+            boolean userSetBrightnessChanged) {
         mDisplayPowerRequest = displayPowerRequest;
         mTargetDisplayState = targetDisplayState;
+        mLastUserSetScreenBrightness = lastUserSetScreenBrightness;
+        mUserSetBrightnessChanged = userSetBrightnessChanged;
     }
 
     public DisplayManagerInternal.DisplayPowerRequest getDisplayPowerRequest() {
@@ -45,18 +55,30 @@
         return mTargetDisplayState;
     }
 
+
+    public float getLastUserSetScreenBrightness() {
+        return mLastUserSetScreenBrightness;
+    }
+
+    public boolean isUserSetBrightnessChanged() {
+        return mUserSetBrightnessChanged;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof StrategySelectionRequest)) {
             return false;
         }
         StrategySelectionRequest other = (StrategySelectionRequest) obj;
-        return Objects.equals(other.getDisplayPowerRequest(), getDisplayPowerRequest())
-                && other.getTargetDisplayState() == getTargetDisplayState();
+        return Objects.equals(mDisplayPowerRequest, other.getDisplayPowerRequest())
+                && mTargetDisplayState == other.getTargetDisplayState()
+                && mLastUserSetScreenBrightness == other.getLastUserSetScreenBrightness()
+                && mUserSetBrightnessChanged == other.isUserSetBrightnessChanged();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mDisplayPowerRequest, mTargetDisplayState);
+        return Objects.hash(mDisplayPowerRequest, mTargetDisplayState,
+                mLastUserSetScreenBrightness, mUserSetBrightnessChanged);
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 08d4cfd..4be7332 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.DisplayManagerInternal;
 import android.os.PowerManager;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -27,9 +28,11 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.display.AutomaticBrightnessController;
+import com.android.server.display.DisplayBrightnessState;
 import com.android.server.display.brightness.BrightnessEvent;
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.brightness.BrightnessUtils;
+import com.android.server.display.brightness.StrategySelectionNotifyRequest;
 
 import java.io.PrintWriter;
 
@@ -40,7 +43,8 @@
  * that it is being executed from the power thread, and hence doesn't synchronize
  * any of its resources
  */
-public class AutomaticBrightnessStrategy {
+public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2
+        implements DisplayBrightnessStrategy{
     private final Context mContext;
     // The DisplayId of the associated logical display
     private final int mDisplayId;
@@ -88,7 +92,12 @@
     @Nullable
     private BrightnessConfiguration mBrightnessConfiguration;
 
+    // Indicates if the strategy is already configured for a request, in which case we wouldn't
+    // want to re-evaluate the auto-brightness state
+    private boolean mIsConfigured;
+
     public AutomaticBrightnessStrategy(Context context, int displayId) {
+        super(context, displayId);
         mContext = context;
         mDisplayId = displayId;
         mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
@@ -112,7 +121,7 @@
         mAutoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness()
                 && !(targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze);
         final int autoBrightnessState = mIsAutoBrightnessEnabled
-                    && brightnessReason != BrightnessReason.REASON_FOLLOWER
+                && brightnessReason != BrightnessReason.REASON_FOLLOWER
                 ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
                 : mAutoBrightnessDisabledDueToDisplayOff
                         ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
@@ -120,12 +129,36 @@
 
         accommodateUserBrightnessChanges(userSetBrightnessChanged, lastUserSetScreenBrightness,
                 policy, targetDisplayState, mBrightnessConfiguration, autoBrightnessState);
+        mIsConfigured = true;
+    }
+
+    public void setIsConfigured(boolean configure) {
+        mIsConfigured = configure;
     }
 
     public boolean isAutoBrightnessEnabled() {
         return mIsAutoBrightnessEnabled;
     }
 
+    /**
+     * Validates if the auto-brightness strategy is valid or not considering the current system
+     * state.
+     */
+    public boolean isAutoBrightnessValid() {
+        boolean isValid = false;
+        if (isAutoBrightnessEnabled()) {
+            float brightness = (mAutomaticBrightnessController != null)
+                    ? mAutomaticBrightnessController.getAutomaticScreenBrightness(null)
+                    : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            if (BrightnessUtils.isValidBrightnessValue(brightness)
+                    || brightness == PowerManager.BRIGHTNESS_OFF_FLOAT) {
+                isValid = true;
+            }
+        }
+        setAutoBrightnessApplied(isValid);
+        return isValid;
+    }
+
     public boolean isAutoBrightnessDisabledDueToDisplayOff() {
         return mAutoBrightnessDisabledDueToDisplayOff;
     }
@@ -217,6 +250,29 @@
         mTemporaryAutoBrightnessAdjustment = temporaryAutoBrightnessAdjustment;
     }
 
+    @Override
+    public DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_AUTOMATIC);
+        BrightnessEvent brightnessEvent = new BrightnessEvent(mDisplayId);
+        float brightness = getAutomaticScreenBrightness(brightnessEvent);
+        return new DisplayBrightnessState.Builder()
+                .setBrightness(brightness)
+                .setSdrBrightness(brightness)
+                .setBrightnessReason(brightnessReason)
+                .setDisplayBrightnessStrategyName(getName())
+                .setIsSlowChange(hasAppliedAutoBrightness()
+                        && !getAutoBrightnessAdjustmentChanged())
+                .setBrightnessEvent(brightnessEvent)
+                .build();
+    }
+
+    @Override
+    public String getName() {
+        return "AutomaticBrightnessStrategy";
+    }
+
     /**
      * Dumps the state of this class.
      */
@@ -238,6 +294,26 @@
                 + mAutoBrightnessAdjustmentReasonsFlags);
     }
 
+    @Override
+    public void strategySelectionPostProcessor(
+            StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
+        if (!mIsConfigured) {
+            setAutoBrightnessState(strategySelectionNotifyRequest.getTargetDisplayState(),
+                    strategySelectionNotifyRequest.isAllowAutoBrightnessWhileDozingConfig(),
+                    strategySelectionNotifyRequest.getSelectedDisplayBrightnessStrategy()
+                            .getReason(),
+                    strategySelectionNotifyRequest.getDisplayPowerRequest().policy,
+                    strategySelectionNotifyRequest.getLastUserSetScreenBrightness(),
+                    strategySelectionNotifyRequest.isUserSetBrightnessChanged());
+        }
+        mIsConfigured = false;
+    }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_AUTOMATIC;
+    }
+
     /**
      * Indicates if any auto-brightness adjustments have happened since the last auto-brightness was
      * set.
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2.java
new file mode 100644
index 0000000..25e8b23
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2.java
@@ -0,0 +1,430 @@
+/*
+ * 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.server.display.brightness.strategy;
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.display.BrightnessConfiguration;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.view.Display;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.AutomaticBrightnessController;
+import com.android.server.display.brightness.BrightnessEvent;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.BrightnessUtils;
+import com.android.server.display.feature.DisplayManagerFlags;
+
+import java.io.PrintWriter;
+
+/**
+ * Helps manage the brightness based on the ambient environment (Ambient Light/lux sensor) using
+ * mappings from lux to nits to brightness, configured in the
+ * {@link com.android.server.display.DisplayDeviceConfig} class. This class inherently assumes
+ * that it is being executed from the power thread, and hence doesn't synchronize
+ * any of its resources
+ *
+ * @deprecated This class is relevant only while the
+ * {@link DisplayManagerFlags#isRefactorDisplayPowerControllerEnabled()} is not fully rolled out.
+ * Till then, please replicated your changes to {@link AutomaticBrightnessStrategy} as well.
+ */
+@Deprecated
+public class AutomaticBrightnessStrategy2 {
+    private final Context mContext;
+    // The DisplayId of the associated logical display
+    private final int mDisplayId;
+    // The last auto brightness adjustment that was set by the user and is not temporary. Set to
+    // Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
+    private float mAutoBrightnessAdjustment;
+    // The pending auto brightness adjustment that will take effect on the next power state update.
+    private float mPendingAutoBrightnessAdjustment;
+    // The temporary auto brightness adjustment. This was historically used when a user interacts
+    // with the adjustment slider but hasn't settled on a choice yet.
+    // Set to PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set.
+    private float mTemporaryAutoBrightnessAdjustment;
+    // Indicates if the temporary auto brightness adjustment has been applied while updating the
+    // associated display brightness
+    private boolean mAppliedTemporaryAutoBrightnessAdjustment;
+    // Indicates if the auto brightness adjustment has happened.
+    private boolean mAutoBrightnessAdjustmentChanged;
+    // Indicates the reasons for the auto-brightness adjustment
+    private int mAutoBrightnessAdjustmentReasonsFlags = 0;
+    // Indicates if the short term model should be reset before fetching the new brightness
+    // Todo(273543270): Short term model is an internal information of
+    //  AutomaticBrightnessController and shouldn't be exposed outside of that class
+    private boolean mShouldResetShortTermModel = false;
+    // Remembers whether the auto-brightness has been applied in the latest brightness update.
+    private boolean mAppliedAutoBrightness = false;
+    // The controller for the automatic brightness level.
+    @Nullable
+    private AutomaticBrightnessController mAutomaticBrightnessController;
+    // The system setting denoting if the auto-brightness for the current user is enabled or not
+    private boolean mUseAutoBrightness = false;
+    // Indicates if the auto-brightness is currently enabled or not. It's possible that even if
+    // the user has enabled the auto-brightness from the settings, it is disabled because the
+    // display is off
+    private boolean mIsAutoBrightnessEnabled = false;
+    // Indicates if auto-brightness is disabled due to the display being off. Needed for metric
+    // purposes.
+    private boolean mAutoBrightnessDisabledDueToDisplayOff;
+    // If the auto-brightness model for the last manual changes done by the user.
+    private boolean mIsShortTermModelActive = false;
+
+    // The BrightnessConfiguration currently being used
+    // Todo(273543270): BrightnessConfiguration is an internal implementation detail of
+    //  AutomaticBrightnessController, and AutomaticBrightnessStrategy shouldn't be aware of its
+    //  existence.
+    @Nullable
+    private BrightnessConfiguration mBrightnessConfiguration;
+
+    public AutomaticBrightnessStrategy2(Context context, int displayId) {
+        mContext = context;
+        mDisplayId = displayId;
+        mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
+        mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+    }
+
+    /**
+     * Sets up the automatic brightness states of this class. Also configures
+     * AutomaticBrightnessController accounting for any manual changes made by the user.
+     */
+    public void setAutoBrightnessState(int targetDisplayState,
+            boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
+            float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
+        final boolean autoBrightnessEnabledInDoze =
+                allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE;
+        mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
+                && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze)
+                && brightnessReason != BrightnessReason.REASON_OVERRIDE
+                && mAutomaticBrightnessController != null;
+        mAutoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness()
+                && !(targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze);
+        final int autoBrightnessState = mIsAutoBrightnessEnabled
+                && brightnessReason != BrightnessReason.REASON_FOLLOWER
+                ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
+                : mAutoBrightnessDisabledDueToDisplayOff
+                        ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
+                        : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
+
+        accommodateUserBrightnessChanges(userSetBrightnessChanged, lastUserSetScreenBrightness,
+                policy, targetDisplayState, mBrightnessConfiguration, autoBrightnessState);
+    }
+
+    public boolean isAutoBrightnessEnabled() {
+        return mIsAutoBrightnessEnabled;
+    }
+
+    public boolean isAutoBrightnessDisabledDueToDisplayOff() {
+        return mAutoBrightnessDisabledDueToDisplayOff;
+    }
+
+    /**
+     * Updates the {@link BrightnessConfiguration} that is currently being used by the associated
+     * display.
+     */
+    public void setBrightnessConfiguration(BrightnessConfiguration brightnessConfiguration,
+            boolean shouldResetShortTermModel) {
+        mBrightnessConfiguration = brightnessConfiguration;
+        setShouldResetShortTermModel(shouldResetShortTermModel);
+    }
+
+    /**
+     * Promotes the pending auto-brightness adjustments which are yet to be applied to the current
+     * adjustments. Note that this is not applying the new adjustments to the AutoBrightness mapping
+     * strategies, but is only accommodating the changes in this class.
+     */
+    public boolean processPendingAutoBrightnessAdjustments() {
+        mAutoBrightnessAdjustmentChanged = false;
+        if (Float.isNaN(mPendingAutoBrightnessAdjustment)) {
+            return false;
+        }
+        if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) {
+            mPendingAutoBrightnessAdjustment = Float.NaN;
+            return false;
+        }
+        mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment;
+        mPendingAutoBrightnessAdjustment = Float.NaN;
+        mTemporaryAutoBrightnessAdjustment = Float.NaN;
+        mAutoBrightnessAdjustmentChanged = true;
+        return true;
+    }
+
+    /**
+     * Updates the associated AutomaticBrightnessController
+     */
+    public void setAutomaticBrightnessController(
+            AutomaticBrightnessController automaticBrightnessController) {
+        if (automaticBrightnessController == mAutomaticBrightnessController) {
+            return;
+        }
+        if (mAutomaticBrightnessController != null) {
+            mAutomaticBrightnessController.stop();
+        }
+        mAutomaticBrightnessController = automaticBrightnessController;
+    }
+
+    /**
+     * Returns if the auto-brightness of the associated display has been enabled or not
+     */
+    public boolean shouldUseAutoBrightness() {
+        return mUseAutoBrightness;
+    }
+
+    /**
+     * Sets the auto-brightness state of the associated display. Called when the user makes a change
+     * in the system setting to enable/disable the auto-brightness.
+     */
+    public void setUseAutoBrightness(boolean useAutoBrightness) {
+        mUseAutoBrightness = useAutoBrightness;
+    }
+
+    /**
+     * Returns if the user made brightness change events(Typically when they interact with the
+     * brightness slider) were accommodated in the auto-brightness mapping strategies. This doesn't
+     * account for the latest changes that have been made by the user.
+     */
+    public boolean isShortTermModelActive() {
+        return mIsShortTermModelActive;
+    }
+
+    /**
+     * Sets the pending auto-brightness adjustments in the system settings. Executed
+     * when there is a change in the brightness system setting, or when there is a user switch.
+     */
+    public void updatePendingAutoBrightnessAdjustments() {
+        final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT);
+        mPendingAutoBrightnessAdjustment = Float.isNaN(adj) ? Float.NaN
+                : BrightnessUtils.clampBrightnessAdjustment(adj);
+    }
+
+    /**
+     * Sets the temporary auto-brightness adjustments
+     */
+    public void setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment) {
+        mTemporaryAutoBrightnessAdjustment = temporaryAutoBrightnessAdjustment;
+    }
+
+    /**
+     * Dumps the state of this class.
+     */
+    public void dump(PrintWriter writer) {
+        writer.println("AutomaticBrightnessStrategy:");
+        writer.println("  mDisplayId=" + mDisplayId);
+        writer.println("  mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
+        writer.println("  mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment);
+        writer.println(
+                "  mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
+        writer.println("  mShouldResetShortTermModel=" + mShouldResetShortTermModel);
+        writer.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
+        writer.println("  mAutoBrightnessAdjustmentChanged=" + mAutoBrightnessAdjustmentChanged);
+        writer.println("  mAppliedTemporaryAutoBrightnessAdjustment="
+                + mAppliedTemporaryAutoBrightnessAdjustment);
+        writer.println("  mUseAutoBrightness=" + mUseAutoBrightness);
+        writer.println("  mWasShortTermModelActive=" + mIsShortTermModelActive);
+        writer.println("  mAutoBrightnessAdjustmentReasonsFlags="
+                + mAutoBrightnessAdjustmentReasonsFlags);
+    }
+
+    /**
+     * Indicates if any auto-brightness adjustments have happened since the last auto-brightness was
+     * set.
+     */
+    public boolean getAutoBrightnessAdjustmentChanged() {
+        return mAutoBrightnessAdjustmentChanged;
+    }
+
+    /**
+     * Returns whether the latest temporary auto-brightness adjustments have been applied or not
+     */
+    public boolean isTemporaryAutoBrightnessAdjustmentApplied() {
+        return mAppliedTemporaryAutoBrightnessAdjustment;
+    }
+
+    /**
+     * Evaluates the target automatic brightness of the associated display.
+     * @param brightnessEvent Event object to populate with details about why the specific
+     *                        brightness was chosen.
+     */
+    public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
+        float brightness = (mAutomaticBrightnessController != null)
+                ? mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent)
+                : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        adjustAutomaticBrightnessStateIfValid(brightness);
+        return brightness;
+    }
+
+    /**
+     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
+     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
+     * the initial brightness in doze mode.
+     * @param brightnessEvent Event object to populate with details about why the specific
+     *                        brightness was chosen.
+     */
+    public float getAutomaticScreenBrightnessBasedOnLastObservedLux(
+            BrightnessEvent brightnessEvent) {
+        float brightness = (mAutomaticBrightnessController != null)
+                ? mAutomaticBrightnessController
+                .getAutomaticScreenBrightnessBasedOnLastObservedLux(brightnessEvent)
+                : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        adjustAutomaticBrightnessStateIfValid(brightness);
+        return brightness;
+    }
+
+    /**
+     * Gets the auto-brightness adjustment flag change reason
+     */
+    public int getAutoBrightnessAdjustmentReasonsFlags() {
+        return mAutoBrightnessAdjustmentReasonsFlags;
+    }
+
+    /**
+     * Returns if the auto brightness has been applied
+     */
+    public boolean hasAppliedAutoBrightness() {
+        return mAppliedAutoBrightness;
+    }
+
+    /**
+     * Used to adjust the state of this class when the automatic brightness value for the
+     * associated display is valid
+     */
+    @VisibleForTesting
+    void adjustAutomaticBrightnessStateIfValid(float brightnessState) {
+        mAutoBrightnessAdjustmentReasonsFlags = isTemporaryAutoBrightnessAdjustmentApplied()
+                ? BrightnessReason.ADJUSTMENT_AUTO_TEMP
+                : BrightnessReason.ADJUSTMENT_AUTO;
+        float newAutoBrightnessAdjustment =
+                (mAutomaticBrightnessController != null)
+                        ? mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()
+                        : 0.0f;
+        if (!Float.isNaN(newAutoBrightnessAdjustment)
+                && mAutoBrightnessAdjustment != newAutoBrightnessAdjustment) {
+            // If the auto-brightness controller has decided to change the adjustment value
+            // used, make sure that's reflected in settings.
+            putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment);
+        } else {
+            mAutoBrightnessAdjustmentReasonsFlags = 0;
+        }
+    }
+
+    /**
+     * Sets up the system to reset the short term model. Note that this will not reset the model
+     * right away, but ensures that the reset happens whenever the next brightness change happens
+     */
+    @VisibleForTesting
+    void setShouldResetShortTermModel(boolean shouldResetShortTermModel) {
+        mShouldResetShortTermModel = shouldResetShortTermModel;
+    }
+
+    @VisibleForTesting
+    boolean shouldResetShortTermModel() {
+        return mShouldResetShortTermModel;
+    }
+
+    @VisibleForTesting
+    float getAutoBrightnessAdjustment() {
+        return mAutoBrightnessAdjustment;
+    }
+
+    @VisibleForTesting
+    float getPendingAutoBrightnessAdjustment() {
+        return mPendingAutoBrightnessAdjustment;
+    }
+
+    @VisibleForTesting
+    float getTemporaryAutoBrightnessAdjustment() {
+        return mTemporaryAutoBrightnessAdjustment;
+    }
+
+    @VisibleForTesting
+    void putAutoBrightnessAdjustmentSetting(float adjustment) {
+        if (mDisplayId == Display.DEFAULT_DISPLAY) {
+            mAutoBrightnessAdjustment = adjustment;
+            Settings.System.putFloatForUser(mContext.getContentResolver(),
+                    Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment,
+                    UserHandle.USER_CURRENT);
+        }
+    }
+
+    /**
+     * Sets if the auto-brightness is applied on the latest brightness change.
+     */
+    public void setAutoBrightnessApplied(boolean autoBrightnessApplied) {
+        mAppliedAutoBrightness = autoBrightnessApplied;
+    }
+
+    /**
+     * Accommodates the latest manual changes made by the user. Also updates {@link
+     * AutomaticBrightnessController} about the changes and configures it accordingly.
+     */
+    @VisibleForTesting
+    void accommodateUserBrightnessChanges(boolean userSetBrightnessChanged,
+            float lastUserSetScreenBrightness, int policy, int displayState,
+            BrightnessConfiguration brightnessConfiguration, int autoBrightnessState) {
+        // Update the pending auto-brightness adjustments if any. This typically checks and adjusts
+        // the state of the class if the user moves the brightness slider and has settled to a
+        // different value
+        processPendingAutoBrightnessAdjustments();
+        // Update the temporary auto-brightness adjustments if any. This typically checks and
+        // adjusts the state of this class if the user is in the process of moving the brightness
+        // slider, but hasn't settled to any value yet
+        float autoBrightnessAdjustment = updateTemporaryAutoBrightnessAdjustments();
+        mIsShortTermModelActive = false;
+        // Configure auto-brightness.
+        if (mAutomaticBrightnessController != null) {
+            // Accommodate user changes if any in the auto-brightness model
+            mAutomaticBrightnessController.configure(autoBrightnessState,
+                    brightnessConfiguration,
+                    lastUserSetScreenBrightness,
+                    userSetBrightnessChanged, autoBrightnessAdjustment,
+                    mAutoBrightnessAdjustmentChanged, policy, displayState,
+                    mShouldResetShortTermModel);
+            mShouldResetShortTermModel = false;
+            // We take note if the user brightness point is still being used in the current
+            // auto-brightness model.
+            mIsShortTermModelActive = mAutomaticBrightnessController.hasUserDataPoints();
+        }
+    }
+
+    /**
+     * Evaluates if there are any temporary auto-brightness adjustments which is not applied yet.
+     * Temporary brightness adjustments happen when the user moves the brightness slider in the
+     * auto-brightness mode, but hasn't settled to a value yet
+     */
+    private float updateTemporaryAutoBrightnessAdjustments() {
+        mAppliedTemporaryAutoBrightnessAdjustment =
+                !Float.isNaN(mTemporaryAutoBrightnessAdjustment);
+        // We do not update the mAutoBrightnessAdjustment with mTemporaryAutoBrightnessAdjustment
+        // since we have not settled to a value yet
+        return mAppliedTemporaryAutoBrightnessAdjustment
+                ? mTemporaryAutoBrightnessAdjustment : mAutoBrightnessAdjustment;
+    }
+
+    /**
+     * Returns the auto-brightness adjustment that is set in the system setting.
+     */
+    private float getAutoBrightnessAdjustmentSetting() {
+        final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT);
+        return Float.isNaN(adj) ? 0.0f : BrightnessUtils.clampBrightnessAdjustment(adj);
+    }
+}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
index 11edde9..9c1acea 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
@@ -53,6 +53,11 @@
     }
 
     @Override
+    public int getReason() {
+        return BrightnessReason.REASON_BOOST;
+    }
+
+    @Override
     public void dump(PrintWriter writer) {}
 
     @Override
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
index 7b49957..61dd6d5 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
@@ -45,6 +45,11 @@
     String getName();
 
     /**
+     * Returns the reason for the change of the brightness
+     */
+    int getReason();
+
+    /**
      * Dumps the state of the Strategy
      * @param writer
      */
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
index 5afdc42..1f7efd1 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
@@ -53,4 +53,9 @@
             StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
         // DO NOTHING
     }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_DOZE;
+    }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
index 0650c1c..baac276 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
@@ -89,4 +89,9 @@
             StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
         // DO NOTHING
     }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_FOLLOWER;
+    }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
index bf37ee0..4abd028 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
@@ -51,4 +51,9 @@
             StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
         // DO NOTHING
     }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_UNKNOWN;
+    }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
index d2bb1e2..64dc47c 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
@@ -79,4 +79,9 @@
             StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
         // DO NOTHING
     }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_OFFLOAD;
+    }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
index 653170c..9605a88 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
@@ -52,4 +52,9 @@
             StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
         // DO NOTHING
     }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_OVERRIDE;
+    }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
index f0cce23..c9dc298 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
@@ -53,4 +53,9 @@
             StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
         // DO NOTHING
     }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_SCREEN_OFF;
+    }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
index 91e1d09..6a691d1 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
@@ -80,4 +80,9 @@
             StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
         // DO NOTHING
     }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_TEMPORARY;
+    }
 }
diff --git a/services/core/java/com/android/server/flags/compaction.aconfig b/services/core/java/com/android/server/flags/compaction.aconfig
index 067a1c9..58cc560 100644
--- a/services/core/java/com/android/server/flags/compaction.aconfig
+++ b/services/core/java/com/android/server/flags/compaction.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.server.flags"
-container: "system"
 
 flag {
     name: "disable_system_compaction"
diff --git a/services/core/java/com/android/server/flags/pinner.aconfig b/services/core/java/com/android/server/flags/pinner.aconfig
index 16a45cd..606a6be 100644
--- a/services/core/java/com/android/server/flags/pinner.aconfig
+++ b/services/core/java/com/android/server/flags/pinner.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.server.flags"
-container: "system"
 
 flag {
     name: "pin_webview"
diff --git a/services/core/java/com/android/server/flags/services.aconfig b/services/core/java/com/android/server/flags/services.aconfig
index 8e0eb05..10b5eff 100644
--- a/services/core/java/com/android/server/flags/services.aconfig
+++ b/services/core/java/com/android/server/flags/services.aconfig
@@ -1,5 +1,4 @@
 package: "com.android.server.flags"
-container: "system"
 
 flag {
      namespace: "wear_frameworks"
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
index 5be0735..d494be5 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionBackupHelper.java
@@ -17,6 +17,7 @@
 package com.android.server.grammaticalinflection;
 
 import android.app.backup.BackupManager;
+import android.content.AttributionSource;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -30,6 +31,7 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
 import java.time.Clock;
 import java.time.Duration;
 import java.util.HashMap;
@@ -47,6 +49,7 @@
     private final PackageManager mPackageManager;
     private final GrammaticalInflectionService mGrammaticalGenderService;
     private final Clock mClock;
+    private final AttributionSource mAttributionSource;
 
     static class StagedData {
         final long mCreationTimeMillis;
@@ -58,8 +61,9 @@
         }
     }
 
-    public GrammaticalInflectionBackupHelper(GrammaticalInflectionService grammaticalGenderService,
-            PackageManager packageManager) {
+    public GrammaticalInflectionBackupHelper(AttributionSource attributionSource,
+            GrammaticalInflectionService grammaticalGenderService, PackageManager packageManager) {
+        mAttributionSource = attributionSource;
         mGrammaticalGenderService = grammaticalGenderService;
         mPackageManager = packageManager;
         mClock = Clock.systemUTC();
@@ -115,6 +119,23 @@
         }
     }
 
+    /**
+     * Returns the system-gender to be backed up as a data-blob.
+     */
+    public byte[] getSystemBackupPayload(int userId) {
+        int gender = mGrammaticalGenderService.getSystemGrammaticalGender(mAttributionSource,
+                userId);
+        return intToByteArray(gender);
+    }
+
+    /**
+     * Restores the system-gender that were previously backed up.
+     */
+    public void applyRestoredSystemPayload(byte[] payload, int userId) {
+        int gender = convertByteArrayToInt(payload);
+        mGrammaticalGenderService.setSystemWideGrammaticalGender(gender, userId);
+    }
+
     private boolean hasSetBeforeRestoring(String pkgName, int userId) {
         return mGrammaticalGenderService.getApplicationGrammaticalGender(pkgName, userId)
                 != Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
@@ -157,6 +178,17 @@
         }
     }
 
+    private byte[] intToByteArray(final int gender) {
+        ByteBuffer bb = ByteBuffer.allocate(4);
+        bb.putInt(gender);
+        return bb.array();
+    }
+
+    private int convertByteArrayToInt(byte[] intBytes) {
+        ByteBuffer byteBuffer = ByteBuffer.wrap(intBytes);
+        return byteBuffer.getInt();
+    }
+
     private HashMap<String, Integer> readFromByteArray(byte[] payload) {
         HashMap<String, Integer> data = new HashMap<>();
 
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
index c2c82ed..2816d08 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
@@ -62,5 +62,16 @@
      * Whether the package can get the system grammatical gender or not.
      */
     public abstract boolean canGetSystemGrammaticalGender(int uid, @Nullable String packageName);
+
+
+    /**
+     * Returns the system-gender to be backed up as a data-blob.
+     */
+    public abstract @Nullable byte[] getSystemBackupPayload(int userId);
+
+    /**
+     * Restores the system-gender that were previously backed up.
+     */
+    public abstract void applyRestoredSystemPayload(byte[] payload, int userId);
 }
 
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 96d4bda..93a71b9 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -102,7 +102,8 @@
         mContext = context;
         mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
-        mBackupHelper = new GrammaticalInflectionBackupHelper(this, context.getPackageManager());
+        mBackupHelper = new GrammaticalInflectionBackupHelper(mContext.getAttributionSource(), this,
+                context.getPackageManager());
         mBinderService = new GrammaticalInflectionBinderService();
         mPermissionManager = context.getSystemService(PermissionManager.class);
     }
@@ -176,6 +177,18 @@
         }
 
         @Override
+        @Nullable
+        public byte[] getSystemBackupPayload(int userId) {
+            isCallerAllowed();
+            return mBackupHelper.getSystemBackupPayload(userId);
+        }
+
+        @Override
+        public void applyRestoredSystemPayload(byte[] payload, int userId) {
+            mBackupHelper.applyRestoredSystemPayload(payload, userId);
+        }
+
+        @Override
         public int getSystemGrammaticalGender(int userId) {
             return checkSystemTermsOfAddressIsEnabled()
                     ? GrammaticalInflectionService.this.getSystemGrammaticalGender(
@@ -290,6 +303,7 @@
                     userId,
                     grammaticalGender != GRAMMATICAL_GENDER_NOT_SPECIFIED,
                     preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED);
+            GrammaticalInflectionBackupHelper.notifyBackupManager();
         } catch (RemoteException e) {
             Log.w(TAG, "Can not update configuration", e);
         }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c6a48ec..1d07eee 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1336,77 +1336,78 @@
             Context context,
             @Nullable ServiceThread serviceThreadForTesting,
             @Nullable InputMethodBindingController bindingControllerForTesting) {
-        mContext = context;
-        mRes = context.getResources();
-        SecureSettingsWrapper.onStart(mContext);
-        // TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading
-        // additional subtypes in switchUserOnHandlerLocked().
-        final ServiceThread thread =
-                serviceThreadForTesting != null
-                        ? serviceThreadForTesting
-                        : new ServiceThread(
-                                HANDLER_THREAD_NAME,
-                                Process.THREAD_PRIORITY_FOREGROUND,
-                                true /* allowIo */);
-        thread.start();
-        mHandler = Handler.createAsync(thread.getLooper(), this);
-        SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler);
-        mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null
-                ? serviceThreadForTesting.getLooper() : Looper.getMainLooper());
-        // Note: SettingsObserver doesn't register observers in its constructor.
-        mSettingsObserver = new SettingsObserver(mHandler);
-        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
-        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
-        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
-        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
-        mImePlatformCompatUtils = new ImePlatformCompatUtils();
-        mInputMethodDeviceConfigs = new InputMethodDeviceConfigs();
-        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
-
-        mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
-
-        mShowOngoingImeSwitcherForPhones = false;
-
-        AdditionalSubtypeMapRepository.initialize(mHandler);
-
-        final int userId = mActivityManagerInternal.getCurrentUserId();
-
-        // mSettings should be created before buildInputMethodListLocked
-        mSettings = InputMethodSettings.createEmptyMap(userId);
-
-        mSwitchingController =
-                InputMethodSubtypeSwitchingController.createInstanceLocked(context,
-                        mSettings.getMethodMap(), userId);
-        mHardwareKeyboardShortcutController =
-                new HardwareKeyboardShortcutController(mSettings.getMethodMap(),
-                        mSettings.getUserId());
-        mMenuController = new InputMethodMenuController(this);
-        mBindingController =
-                bindingControllerForTesting != null
-                        ? bindingControllerForTesting
-                        : new InputMethodBindingController(this);
-        mAutofillController = new AutofillSuggestionsController(this);
-
-        mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
-        mVisibilityApplier = new DefaultImeVisibilityApplier(this);
-
-        mClientController = new ClientController(mPackageManagerInternal);
         synchronized (ImfLock.class) {
+            mContext = context;
+            mRes = context.getResources();
+            SecureSettingsWrapper.onStart(mContext);
+
+            // TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading
+            // additional subtypes in switchUserOnHandlerLocked().
+            final ServiceThread thread =
+                    serviceThreadForTesting != null
+                            ? serviceThreadForTesting
+                            : new ServiceThread(
+                                    HANDLER_THREAD_NAME,
+                                    Process.THREAD_PRIORITY_FOREGROUND,
+                                    true /* allowIo */);
+            thread.start();
+            mHandler = Handler.createAsync(thread.getLooper(), this);
+            SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler);
+            mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null
+                    ? serviceThreadForTesting.getLooper() : Looper.getMainLooper());
+            // Note: SettingsObserver doesn't register observers in its constructor.
+            mSettingsObserver = new SettingsObserver(mHandler);
+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+            mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+            mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+            mImePlatformCompatUtils = new ImePlatformCompatUtils();
+            mInputMethodDeviceConfigs = new InputMethodDeviceConfigs();
+            mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+
+            mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
+
+            mShowOngoingImeSwitcherForPhones = false;
+
+            AdditionalSubtypeMapRepository.initialize(mHandler);
+
+            final int userId = mActivityManagerInternal.getCurrentUserId();
+
+            // mSettings should be created before buildInputMethodListLocked
+            mSettings = InputMethodSettings.createEmptyMap(userId);
+
+            mSwitchingController =
+                    InputMethodSubtypeSwitchingController.createInstanceLocked(context,
+                            mSettings.getMethodMap(), userId);
+            mHardwareKeyboardShortcutController =
+                    new HardwareKeyboardShortcutController(mSettings.getMethodMap(),
+                            mSettings.getUserId());
+            mMenuController = new InputMethodMenuController(this);
+            mBindingController =
+                    bindingControllerForTesting != null
+                            ? bindingControllerForTesting
+                            : new InputMethodBindingController(this);
+            mAutofillController = new AutofillSuggestionsController(this);
+
+            mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
+            mVisibilityApplier = new DefaultImeVisibilityApplier(this);
+
+            mClientController = new ClientController(mPackageManagerInternal);
             mClientController.addClientControllerCallback(c -> onClientRemoved(c));
             mImeBindingState = ImeBindingState.newEmptyState();
-        }
 
-        mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
-                com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
-        mNonPreemptibleInputMethods = mRes.getStringArray(
-                com.android.internal.R.array.config_nonPreemptibleInputMethods);
-        IntConsumer toolTypeConsumer =
-                Flags.useHandwritingListenerForTooltype()
-                        ? toolType -> onUpdateEditorToolType(toolType) : null;
-        Runnable discardDelegationTextRunnable = () -> discardHandwritingDelegationText();
-        mHwController = new HandwritingModeController(mContext, thread.getLooper(),
-                new InkWindowInitializer(), toolTypeConsumer, discardDelegationTextRunnable);
-        registerDeviceListenerAndCheckStylusSupport();
+            mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
+                    com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
+            mNonPreemptibleInputMethods = mRes.getStringArray(
+                    com.android.internal.R.array.config_nonPreemptibleInputMethods);
+            IntConsumer toolTypeConsumer =
+                    Flags.useHandwritingListenerForTooltype()
+                            ? toolType -> onUpdateEditorToolType(toolType) : null;
+            Runnable discardDelegationTextRunnable = () -> discardHandwritingDelegationText();
+            mHwController = new HandwritingModeController(mContext, thread.getLooper(),
+                    new InkWindowInitializer(), toolTypeConsumer, discardDelegationTextRunnable);
+            registerDeviceListenerAndCheckStylusSupport();
+        }
     }
 
     @GuardedBy("ImfLock.class")
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 5931744..19562ef 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -102,8 +102,10 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.ICeStorageLockEventListener;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.security.AndroidKeyStoreMaintenance;
@@ -338,6 +340,8 @@
     private final CopyOnWriteArrayList<LockSettingsStateListener> mLockSettingsStateListeners =
             new CopyOnWriteArrayList<>();
 
+    private final StorageManagerInternal mStorageManagerInternal;
+
     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
     // devices. The most basic of these is to show/hide notifications about missing features until
     // the user unlocks the account and credential-encrypted storage is available.
@@ -577,6 +581,10 @@
             return null;
         }
 
+        public StorageManagerInternal getStorageManagerInternal() {
+            return LocalServices.getService(StorageManagerInternal.class);
+        }
+
         public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
             return new SyntheticPasswordManager(getContext(), storage, getUserManager(),
                     new PasswordSlotManager());
@@ -672,6 +680,7 @@
         mNotificationManager = injector.getNotificationManager();
         mUserManager = injector.getUserManager();
         mStorageManager = injector.getStorageManager();
+        mStorageManagerInternal = injector.getStorageManagerInternal();
         mStrongAuthTracker = injector.getStrongAuthTracker();
         mStrongAuthTracker.register(mStrongAuth);
         mGatekeeperPasswords = new LongSparseArray<>();
@@ -925,8 +934,34 @@
         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
         mBiometricDeferredQueue.systemReady(mInjector.getFingerprintManager(),
                 mInjector.getFaceManager(), mInjector.getBiometricManager());
+        if (android.os.Flags.allowPrivateProfile()
+                && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
+            mStorageManagerInternal.registerStorageLockEventListener(mCeStorageLockEventListener);
+        }
     }
 
+    private final ICeStorageLockEventListener mCeStorageLockEventListener =
+            new ICeStorageLockEventListener() {
+                @Override
+                public void onStorageLocked(int userId) {
+                    Slog.i(TAG, "Storage lock event received for " + userId);
+                    if (android.os.Flags.allowPrivateProfile()
+                            && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                            && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
+                        mHandler.post(() -> {
+                            UserProperties userProperties =
+                                    mUserManager.getUserProperties(UserHandle.of(userId));
+                            if (userProperties != null
+                                    && userProperties.getAllowStoppingUserWithDelayedLocking()) {
+                                int strongAuthRequired = LockPatternUtils.StrongAuthTracker
+                                        .getDefaultFlags(mContext);
+                                requireStrongAuth(strongAuthRequired, userId);
+                            }
+                        });
+                    }
+                }};
+
     private void loadEscrowData() {
         mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler);
     }
diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING
index ddf3d76..256d9ba 100644
--- a/services/core/java/com/android/server/locksettings/TEST_MAPPING
+++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING
@@ -24,5 +24,11 @@
                 }
             ]
         }
+    ],
+    "postsubmit": [
+        {
+            // TODO(b/332974906): Promote in presubmit-large.
+            "name": "CtsDevicePolicyManagerTestCases_LockSettings_NoFlakes"
+        }
     ]
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 7b12d86..68e0eaa 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -27,6 +27,10 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -44,7 +48,13 @@
     private final Context mContext;
     private final RankingHandler mRankingHandler;
 
-
+    @UsesReflection(
+            value = {
+                @KeepTarget(
+                        kind = KeepItemKind.CLASS_AND_MEMBERS,
+                        instanceOfClassConstantExclusive = NotificationSignalExtractor.class,
+                        methodName = "<init>")
+            })
     public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config,
             ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) {
         mContext = context;
diff --git a/services/core/java/com/android/server/os/TEST_MAPPING b/services/core/java/com/android/server/os/TEST_MAPPING
index d937af1..50c8964 100644
--- a/services/core/java/com/android/server/os/TEST_MAPPING
+++ b/services/core/java/com/android/server/os/TEST_MAPPING
@@ -45,6 +45,10 @@
     },
     {
       "file_patterns": ["Bugreport[^/]*\\.java"],
+      "name": "CtsRootBugreportTestCases"
+    },
+    {
+      "file_patterns": ["Bugreport[^/]*\\.java"],
       "name": "ShellTests"
     }
   ]
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index e2f4d18..fda4dc6 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -187,7 +187,7 @@
     }
 
     public static boolean isArchivingEnabled() {
-        return Flags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false);
+        return Flags.archiving();
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 1fe49c7..7ef7ce7 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -16,6 +16,8 @@
 
 package com.android.server.pm;
 
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_APEX;
+
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
@@ -399,7 +401,7 @@
             final ParsedPackage parsedPackage;
             try (PackageParser2 packageParser = mPackageParserSupplier.get()) {
                 File apexFile = new File(apexInfo.modulePath);
-                parsedPackage = packageParser.parsePackage(apexFile, 0, false);
+                parsedPackage = packageParser.parsePackage(apexFile, PARSE_APEX, false);
             } catch (PackageParserException e) {
                 throw new PackageManagerException(
                         PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 33b5a70..1e7fdfe 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -306,7 +306,7 @@
                         R.color.black)
                 .setDarkThemeBadgeColors(
                         R.color.white)
-                .setDefaultRestrictions(getDefaultProfileRestrictions())
+                .setDefaultRestrictions(getDefaultPrivateProfileRestrictions())
                 .setDefaultCrossProfileIntentFilters(getDefaultPrivateCrossProfileIntentFilter())
                 .setDefaultUserProperties(new UserProperties.Builder()
                         .setStartWithParent(true)
@@ -430,6 +430,13 @@
         return restrictions;
     }
 
+    @VisibleForTesting
+    static Bundle getDefaultPrivateProfileRestrictions() {
+        final Bundle restrictions = getDefaultProfileRestrictions();
+        restrictions.putBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING, true);
+        return restrictions;
+    }
+
     private static Bundle getDefaultManagedProfileSecureSettings() {
         // Only add String values to the bundle, settings are written as Strings eventually
         final Bundle settings = new Bundle();
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index 9f0a975..8f99d28 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -568,23 +568,25 @@
             int index = 0;
 
             Channel[] channels = getEnergyMeterInfo();
-            for (Channel channel : channels) {
-                PowerMonitor monitor = new PowerMonitor(index++,
-                        PowerMonitor.POWER_MONITOR_TYPE_MEASUREMENT,
-                        getChannelName(channel));
-                monitors.add(monitor);
-                states.add(new PowerMonitorState(monitor, channel.id));
+            if (channels != null) {
+                for (Channel channel : channels) {
+                    PowerMonitor monitor = new PowerMonitor(index++,
+                            PowerMonitor.POWER_MONITOR_TYPE_MEASUREMENT,
+                            getChannelName(channel));
+                    monitors.add(monitor);
+                    states.add(new PowerMonitorState(monitor, channel.id));
+                }
             }
-
             EnergyConsumer[] energyConsumers = getEnergyConsumerInfo();
-            for (EnergyConsumer consumer : energyConsumers) {
-                PowerMonitor monitor = new PowerMonitor(index++,
-                        PowerMonitor.POWER_MONITOR_TYPE_CONSUMER,
-                        getEnergyConsumerName(consumer, energyConsumers));
-                monitors.add(monitor);
-                states.add(new PowerMonitorState(monitor, consumer.id));
+            if (energyConsumers != null) {
+                for (EnergyConsumer consumer : energyConsumers) {
+                    PowerMonitor monitor = new PowerMonitor(index++,
+                            PowerMonitor.POWER_MONITOR_TYPE_CONSUMER,
+                            getEnergyConsumerName(consumer, energyConsumers));
+                    monitors.add(monitor);
+                    states.add(new PowerMonitorState(monitor, consumer.id));
+                }
             }
-
             mPowerMonitors = monitors.toArray(new PowerMonitor[monitors.size()]);
             mPowerMonitorStates = states.toArray(new PowerMonitorState[monitors.size()]);
         }
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 3c0547e..c24240b 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -30,6 +30,7 @@
 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.apex.CompressedApexInfo;
 import android.apex.CompressedApexInfoList;
 import android.content.Context;
@@ -37,6 +38,7 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.hardware.boot.IBootControl;
+import android.hardware.security.secretkeeper.ISecretkeeper;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.Binder;
@@ -52,6 +54,7 @@
 import android.os.ShellCallback;
 import android.os.SystemProperties;
 import android.provider.DeviceConfig;
+import android.security.AndroidKeyStoreMaintenance;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.FastImmutableArraySet;
@@ -68,6 +71,7 @@
 import com.android.server.Watchdog;
 import com.android.server.pm.ApexManager;
 import com.android.server.recoverysystem.hal.BootControlHIDL;
+import com.android.server.utils.Slogf;
 
 import libcore.io.IoUtils;
 
@@ -122,6 +126,8 @@
     static final String LSKF_CAPTURED_TIMESTAMP_PREF = "lskf_captured_timestamp";
     static final String LSKF_CAPTURED_COUNT_PREF = "lskf_captured_count";
 
+    static final String RECOVERY_WIPE_DATA_COMMAND = "--wipe_data";
+
     private final Injector mInjector;
     private final Context mContext;
 
@@ -525,18 +531,57 @@
     @Override // Binder call
     public void rebootRecoveryWithCommand(String command) {
         if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
+
+        boolean isForcedWipe = command != null && command.contains(RECOVERY_WIPE_DATA_COMMAND);
         synchronized (sRequestLock) {
             if (!setupOrClearBcb(true, command)) {
                 Slog.e(TAG, "rebootRecoveryWithCommand failed to setup BCB");
                 return;
             }
 
+            if (isForcedWipe) {
+                deleteSecrets();
+                // TODO: consider adding a dedicated forced-wipe-reboot method to PowerManager and
+                // calling here.
+            }
+
             // Having set up the BCB, go ahead and reboot.
             PowerManager pm = mInjector.getPowerManager();
             pm.reboot(PowerManager.REBOOT_RECOVERY);
         }
     }
 
+    private static void deleteSecrets() {
+        Slogf.w(TAG, "deleteSecrets");
+        try {
+            AndroidKeyStoreMaintenance.deleteAllKeys();
+        } catch (android.security.KeyStoreException e) {
+            Log.wtf(TAG, "Failed to delete all keys from keystore.", e);
+        }
+
+        try {
+            ISecretkeeper secretKeeper = getSecretKeeper();
+            if (secretKeeper != null) {
+                Slogf.i(TAG, "ISecretkeeper.deleteAll();");
+                secretKeeper.deleteAll();
+            }
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failed to delete all secrets from secretkeeper.", e);
+        }
+    }
+
+    private static @Nullable ISecretkeeper getSecretKeeper() {
+        ISecretkeeper result = null;
+        try {
+            result = ISecretkeeper.Stub.asInterface(
+                ServiceManager.waitForDeclaredService(ISecretkeeper.DESCRIPTOR + "/default"));
+        } catch (SecurityException e) {
+            Slog.w(TAG, "Does not have permissions to get AIDL secretkeeper service");
+        }
+
+        return result;
+    }
+
     private void enforcePermissionForResumeOnReboot() {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.RECOVERY)
                 != PackageManager.PERMISSION_GRANTED
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
index 6905802..f6e0168 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
@@ -137,6 +137,27 @@
                 // This will fall into "Case 4" of this function and center the folded screen
                 return getCrop(displaySize, bitmapSize, newSuggestedCrops, rtl);
             }
+
+            // The second exception is if we're on tablet and we're on portrait mode.
+            // In that case, center the wallpaper relatively to landscape and put some parallax.
+            boolean isTablet = mWallpaperDisplayHelper.isLargeScreen()
+                    && !mWallpaperDisplayHelper.isFoldable();
+            if (isTablet && displaySize.x < displaySize.y) {
+                Point rotatedDisplaySize = new Point(displaySize.y, displaySize.x);
+                // compute the crop on landscape (without parallax)
+                Rect landscapeCrop = getCrop(rotatedDisplaySize, bitmapSize, suggestedCrops, rtl);
+                landscapeCrop = noParallax(landscapeCrop, rotatedDisplaySize, bitmapSize, rtl);
+                // compute the crop on portrait at the center of the landscape crop
+                crop = getAdjustedCrop(landscapeCrop, bitmapSize, displaySize, false, rtl, ADD);
+
+                // add some parallax (until the border of the landscape crop without parallax)
+                if (rtl) {
+                    crop.left = landscapeCrop.left;
+                } else {
+                    crop.right = landscapeCrop.right;
+                }
+            }
+
             return getAdjustedCrop(crop, bitmapSize, displaySize, true, rtl, ADD);
         }
 
@@ -472,6 +493,7 @@
                 }
             }
             final Rect cropHint;
+            final SparseArray<Rect> defaultCrops;
 
             // A wallpaper with cropHints = Map.of(ORIENTATION_UNKNOWN, rect) is treated like
             // a wallpaper with cropHints = null and  cropHint = rect.
@@ -483,7 +505,7 @@
             if (multiCrop() && wallpaper.mCropHints.size() > 0) {
                 // Some suggested crops per screen orientation were provided,
                 // use them to compute the default crops for this device
-                SparseArray<Rect> defaultCrops = getDefaultCrops(wallpaper.mCropHints, bitmapSize);
+                defaultCrops = getDefaultCrops(wallpaper.mCropHints, bitmapSize);
                 // Adapt the provided crops to match the actual crops for the default display
                 SparseArray<Rect> updatedCropHints = new SparseArray<>();
                 for (int i = 0; i < wallpaper.mCropHints.size(); i++) {
@@ -514,7 +536,7 @@
                     wallpaper.cropHint.set(bitmapRect);
                 }
                 Point cropSize = new Point(wallpaper.cropHint.width(), wallpaper.cropHint.height());
-                SparseArray<Rect> defaultCrops = getDefaultCrops(new SparseArray<>(), cropSize);
+                defaultCrops = getDefaultCrops(new SparseArray<>(), cropSize);
                 cropHint = getTotalCrop(defaultCrops);
                 cropHint.offset(wallpaper.cropHint.left, wallpaper.cropHint.top);
                 wallpaper.cropHint.set(cropHint);
@@ -523,6 +545,7 @@
                 }
             } else {
                 cropHint = new Rect(wallpaper.cropHint);
+                defaultCrops = null;
             }
 
             if (DEBUG) {
@@ -563,6 +586,33 @@
                     || cropHint.height() > GLHelper.getMaxTextureSize()
                     || cropHint.width() > GLHelper.getMaxTextureSize();
 
+            float sampleSize = Float.MAX_VALUE;
+            if (multiCrop()) {
+                // If all crops for all orientations have more width and height in pixel
+                // than the display for this orientation, downsample the image
+                for (int i = 0; i < defaultCrops.size(); i++) {
+                    int orientation = defaultCrops.keyAt(i);
+                    Rect crop = defaultCrops.valueAt(i);
+                    Point displayForThisOrientation = mWallpaperDisplayHelper
+                            .getDefaultDisplaySizes().get(orientation);
+                    if (displayForThisOrientation == null) continue;
+                    float sampleSizeForThisOrientation = Math.max(1f, Math.min(
+                            crop.width() / displayForThisOrientation.x,
+                            crop.height() / displayForThisOrientation.y));
+                    sampleSize = Math.min(sampleSize, sampleSizeForThisOrientation);
+                }
+                // If the total crop has more width or height than either the max texture size
+                // or twice the largest display dimension, downsample the image
+                int maxCropSize = Math.min(
+                        2 * mWallpaperDisplayHelper.getDefaultDisplayLargestDimension(),
+                        GLHelper.getMaxTextureSize());
+                float minimumSampleSize = Math.max(1f, Math.max(
+                        (float) cropHint.height() / maxCropSize,
+                        (float) cropHint.width()) / maxCropSize);
+                sampleSize = Math.max(sampleSize, minimumSampleSize);
+                needScale = sampleSize > 1f;
+            }
+
             //make sure screen aspect ratio is preserved if width is scaled under screen size
             if (needScale && !multiCrop()) {
                 final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height();
@@ -577,7 +627,8 @@
 
             if (DEBUG_CROP) {
                 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
-                Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);
+                if (multiCrop()) Slog.v(TAG, "defaultCrops: " + defaultCrops);
+                if (!multiCrop()) Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);
                 Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
                 Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
             }
@@ -620,28 +671,17 @@
                     options.inJustDecodeBounds = false;
 
                     final Rect estimateCrop = new Rect(cropHint);
-                    estimateCrop.scale(1f / options.inSampleSize);
+                    if (!multiCrop()) estimateCrop.scale(1f / options.inSampleSize);
+                    else estimateCrop.scale(1f / sampleSize);
                     float hRatio = (float) wpData.mHeight / estimateCrop.height();
-                    if (multiCrop()) {
-                        // make sure the crop height is at most the display largest dimension
-                        hRatio = (float) mWallpaperDisplayHelper.getDefaultDisplayLargestDimension()
-                                / estimateCrop.height();
-                        hRatio = Math.min(hRatio, 1f);
-                    }
                     final int destHeight = (int) (estimateCrop.height() * hRatio);
                     final int destWidth = (int) (estimateCrop.width() * hRatio);
 
                     // We estimated an invalid crop, try to adjust the cropHint to get a valid one.
-                    if (destWidth > GLHelper.getMaxTextureSize()) {
+                    if (!multiCrop() && destWidth > GLHelper.getMaxTextureSize()) {
                         if (DEBUG) {
                             Slog.w(TAG, "Invalid crop dimensions, trying to adjust.");
                         }
-                        if (multiCrop()) {
-                            // clear custom crop guidelines, fallback to system default
-                            wallpaper.mCropHints.clear();
-                            generateCropInternal(wallpaper);
-                            return;
-                        }
 
                         int newHeight = (int) (wpData.mHeight / hRatio);
                         int newWidth = (int) (wpData.mWidth / hRatio);
@@ -658,16 +698,27 @@
                     // We've got the safe cropHint; now we want to scale it properly to
                     // the desired rectangle.
                     // That's a height-biased operation: make it fit the hinted height.
-                    final int safeHeight = (int) (estimateCrop.height() * hRatio + 0.5f);
-                    final int safeWidth = (int) (estimateCrop.width() * hRatio + 0.5f);
+                    final int safeHeight = !multiCrop()
+                            ? (int) (estimateCrop.height() * hRatio + 0.5f)
+                            : (int) (cropHint.height() / sampleSize + 0.5f);
+                    final int safeWidth = !multiCrop()
+                            ? (int) (estimateCrop.width() * hRatio + 0.5f)
+                            : (int) (cropHint.width() / sampleSize + 0.5f);
 
                     if (DEBUG_CROP) {
                         Slog.v(TAG, "Decode parameters:");
-                        Slog.v(TAG, "  cropHint=" + cropHint + ", estimateCrop=" + estimateCrop);
-                        Slog.v(TAG, "  down sampling=" + options.inSampleSize
-                                + ", hRatio=" + hRatio);
-                        Slog.v(TAG, "  dest=" + destWidth + "x" + destHeight);
-                        Slog.v(TAG, "  safe=" + safeWidth + "x" + safeHeight);
+                        if (!multiCrop()) {
+                            Slog.v(TAG,
+                                    "  cropHint=" + cropHint + ", estimateCrop=" + estimateCrop);
+                            Slog.v(TAG, "  down sampling=" + options.inSampleSize
+                                    + ", hRatio=" + hRatio);
+                            Slog.v(TAG, "  dest=" + destWidth + "x" + destHeight);
+                        }
+                        if (multiCrop()) {
+                            Slog.v(TAG, "  cropHint=" + cropHint);
+                            Slog.v(TAG, "  sampleSize=" + sampleSize);
+                        }
+                        Slog.v(TAG, "  targetSize=" + safeWidth + "x" + safeHeight);
                         Slog.v(TAG, "  maxTextureSize=" + GLHelper.getMaxTextureSize());
                     }
 
@@ -682,24 +733,28 @@
 
                     final ImageDecoder.Source srcData =
                             ImageDecoder.createSource(wallpaper.getWallpaperFile());
-                    final int sampleSize = scale;
+                    final int finalScale = scale;
+                    final int rescaledBitmapWidth = (int) (0.5f + bitmapSize.x / sampleSize);
+                    final int rescaledBitmapHeight = (int) (0.5f + bitmapSize.y / sampleSize);
                     Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> {
-                        decoder.setTargetSampleSize(sampleSize);
+                        if (!multiCrop()) decoder.setTargetSampleSize(finalScale);
+                        if (multiCrop()) {
+                            decoder.setTargetSize(rescaledBitmapWidth, rescaledBitmapHeight);
+                        }
                         decoder.setCrop(estimateCrop);
                     });
 
                     record.delete();
 
-                    if (cropped == null) {
+                    if (!multiCrop() && cropped == null) {
                         Slog.e(TAG, "Could not decode new wallpaper");
                     } else {
                         // We are safe to create final crop with safe dimensions now.
-                        final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
-                                safeWidth, safeHeight, true);
+                        final Bitmap finalCrop = multiCrop() ? cropped
+                                : Bitmap.createScaledBitmap(cropped, safeWidth, safeHeight, true);
 
                         if (multiCrop()) {
-                            wallpaper.mSampleSize =
-                                    ((float) cropHint.height()) / finalCrop.getHeight();
+                            wallpaper.mSampleSize = sampleSize;
                         }
 
                         if (DEBUG) {
@@ -718,9 +773,7 @@
                         success = true;
                     }
                 } catch (Exception e) {
-                    if (DEBUG) {
-                        Slog.e(TAG, "Error decoding crop", e);
-                    }
+                    Slog.e(TAG, "Error decoding crop", e);
                 } finally {
                     IoUtils.closeQuietly(bos);
                     IoUtils.closeQuietly(f);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
index 9e1b5d2..3636f5a 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java
@@ -59,6 +59,8 @@
     }
 
     private static final String TAG = WallpaperDisplayHelper.class.getSimpleName();
+    private static final float LARGE_SCREEN_MIN_DP = 600f;
+
     private final SparseArray<DisplayData> mDisplayDatas = new SparseArray<>();
     private final DisplayManager mDisplayManager;
     private final WindowManagerInternal mWindowManagerInternal;
@@ -67,7 +69,8 @@
     // related orientations pairs for foldable (folded orientation, unfolded orientation)
     private final List<Pair<Integer, Integer>> mFoldableOrientationPairs = new ArrayList<>();
 
-    private boolean mIsFoldable;
+    private final boolean mIsFoldable;
+    private boolean mIsLargeScreen = false;
 
     WallpaperDisplayHelper(
             DisplayManager displayManager,
@@ -94,6 +97,9 @@
                     mDefaultDisplaySizes.put(orientation, point);
                 }
             }
+
+            mIsLargeScreen |= (displaySize.x / metric.getDensity() >= LARGE_SCREEN_MIN_DP);
+
             if (populateOrientationPairs) {
                 int orientation = WallpaperManager.getOrientation(displaySize);
                 float newSurface = displaySize.x * displaySize.y
@@ -215,6 +221,13 @@
     }
 
     /**
+     * Return true if any of the screens of the default display is considered large (DP >= 600)
+     */
+    boolean isLargeScreen() {
+        return mIsLargeScreen;
+    }
+
+    /**
      * If a given orientation corresponds to an unfolded orientation on foldable, return the
      * corresponding folded orientation. Otherwise, return UNKNOWN. Always return UNKNOWN if the
      * device is not a foldable.
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 802f196..9a5961a 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -132,6 +132,9 @@
 import com.android.server.wallpaper.WallpaperData.BindSource;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -167,6 +170,13 @@
         }
 
         @Override
+        @UsesReflection(
+                value = {
+                    @KeepTarget(
+                            kind = KeepItemKind.CLASS_AND_MEMBERS,
+                            instanceOfClassConstantExclusive = IWallpaperManagerService.class,
+                            methodName = "<init>")
+                })
         public void onStart() {
             try {
                 final Class<? extends IWallpaperManagerService> klass =
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
index eb170b7..c6b401b 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java
@@ -17,6 +17,9 @@
 package com.android.server.wearable;
 
 import static android.service.wearable.WearableSensingService.HOTWORD_AUDIO_STREAM_BUNDLE_KEY;
+import static android.system.OsConstants.F_GETFL;
+import static android.system.OsConstants.O_ACCMODE;
+import static android.system.OsConstants.O_RDONLY;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -42,6 +45,8 @@
 import android.service.voice.HotwordAudioStream;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.system.OsConstants;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -276,7 +281,10 @@
             ParcelFileDescriptor parcelFileDescriptor,
             @Nullable IWearableSensingCallback wearableSensingCallback,
             RemoteCallback statusCallback) {
-        Slog.i(TAG, "onProvideDataStream in per user service.");
+        Slog.i(
+                TAG,
+                "onProvideDataStream in per user service. Is data stream read-only? "
+                        + isReadOnly(parcelFileDescriptor));
         synchronized (mLock) {
             if (!setUpServiceIfNeeded()) {
                 Slog.w(TAG, "Detection service is not available at this moment.");
@@ -505,10 +513,49 @@
                     String filename,
                     AndroidFuture<ParcelFileDescriptor> futureFromWearableSensingService)
                     throws RemoteException {
-                // TODO(b/331395522): Intercept the PFD received from the app process and verify it
-                // is read-only
-                callbackFromAppProcess.openFile(filename, futureFromWearableSensingService);
+                AndroidFuture<ParcelFileDescriptor> futureFromSystemServer =
+                        new AndroidFuture<ParcelFileDescriptor>()
+                                .whenComplete(
+                                        (pfdFromApp, throwable) -> {
+                                            if (throwable != null) {
+                                                Slog.e(
+                                                        TAG,
+                                                        "Error when reading file " + filename,
+                                                        throwable);
+                                                futureFromWearableSensingService.complete(null);
+                                                return;
+                                            }
+                                            if (isReadOnly(pfdFromApp)) {
+                                                futureFromWearableSensingService.complete(
+                                                        pfdFromApp);
+                                            } else {
+                                                Slog.w(
+                                                        TAG,
+                                                        "Received writable ParcelFileDescriptor"
+                                                            + " from app process. To prevent"
+                                                            + " arbitrary data egress, sending null"
+                                                            + " to WearableSensingService"
+                                                            + " instead.");
+                                                futureFromWearableSensingService.complete(null);
+                                            }
+                                        });
+                callbackFromAppProcess.openFile(filename, futureFromSystemServer);
             }
         };
     }
+
+    private static boolean isReadOnly(ParcelFileDescriptor parcelFileDescriptor) {
+        try {
+            int readMode =
+                    Os.fcntlInt(parcelFileDescriptor.getFileDescriptor(), F_GETFL, 0) & O_ACCMODE;
+            return readMode == O_RDONLY;
+        } catch (ErrnoException ex) {
+            Slog.w(
+                    TAG,
+                    "Error encountered when trying to determine if the parcelFileDescriptor is"
+                        + " read-only. Treating it as not read-only",
+                    ex);
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/webkit/flags.aconfig b/services/core/java/com/android/server/webkit/flags.aconfig
index 84dc1d7..2afbcd6 100644
--- a/services/core/java/com/android/server/webkit/flags.aconfig
+++ b/services/core/java/com/android/server/webkit/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.webkit"
-container: "system"
 
 flag {
     name: "update_service_v2"
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4036d55..207d42b6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -8645,7 +8645,7 @@
 
         // Override starts here.
         final Rect stableInsets = mDisplayContent.getDisplayPolicy().getDecorInsetsInfo(
-                rotation, fullBounds.width(), fullBounds.height()).mLegacyConfigInsets;
+                rotation, fullBounds.width(), fullBounds.height()).mOverrideConfigInsets;
         // This should be the only place override the configuration for ActivityRecord. Override
         // the value if not calculated yet.
         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
@@ -8681,7 +8681,7 @@
             mDisplayContent.getDisplay().getDisplayInfo(info);
             mDisplayContent.computeSizeRanges(info, rotated, info.logicalWidth,
                     info.logicalHeight, mDisplayContent.getDisplayMetrics().density,
-                    inOutConfig, true /* legacyConfig */);
+                    inOutConfig, true /* overrideConfig */);
         }
 
         // It's possible that screen size will be considered in different orientation with or
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index efeb85f..d49a507 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -40,6 +40,10 @@
 import android.os.Bundle;
 import android.text.TextUtils;
 
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -184,6 +188,13 @@
         /**
          * Instantiates the device-specific {@link Provider}.
          */
+        @UsesReflection(
+                value = {
+                        @KeepTarget(
+                                kind = KeepItemKind.CLASS_AND_MEMBERS,
+                                instanceOfClassConstantExclusive = Provider.class,
+                                methodName = "<init>")
+                })
         static Provider fromResources(Resources res) {
             String name = res.getString(
                     com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index cde3e68..739f76e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1007,8 +1007,6 @@
 
     private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
         final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
-        final boolean obscuredChanged = w.mObscured !=
-                mTmpApplySurfaceChangesTransactionState.obscured;
         final RootWindowContainer root = mWmService.mRoot;
 
         if (w.mHasSurface) {
@@ -1107,12 +1105,6 @@
             }
         }
 
-        if (obscuredChanged && w.isVisible() && mWallpaperController.isWallpaperTarget(w)) {
-            // This is the wallpaper target and its obscured state changed... make sure the
-            // current wallpaper's visibility has been updated accordingly.
-            mWallpaperController.updateWallpaperTokens(mDisplayContent.isKeyguardLocked());
-        }
-
         w.handleWindowMovedIfNeeded();
 
         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
@@ -2277,7 +2269,7 @@
         }
 
         computeSizeRanges(mDisplayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig,
-                false /* legacyConfig */);
+                false /* overrideConfig */);
 
         setDisplayInfoOverride();
 
@@ -2414,7 +2406,7 @@
         final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
         displayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
         computeSizeRanges(displayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig,
-                false /* legacyConfig */);
+                false /* overrideConfig */);
         return displayInfo;
     }
 
@@ -2588,11 +2580,10 @@
      * @param dh Display Height in current rotation.
      * @param density Display density.
      * @param outConfig The output configuration to
-     * @param legacyConfig Whether we need to report the legacy result, which is excluding system
-     *                     decorations.
+     * @param overrideConfig Whether we need to report the override config result
      */
     void computeSizeRanges(DisplayInfo displayInfo, boolean rotated,
-            int dw, int dh, float density, Configuration outConfig, boolean legacyConfig) {
+            int dw, int dh, float density, Configuration outConfig, boolean overrideConfig) {
 
         // We need to determine the smallest width that will occur under normal
         // operation.  To this, start with the base screen size and compute the
@@ -2610,10 +2601,12 @@
         displayInfo.smallestNominalAppHeight = 1<<30;
         displayInfo.largestNominalAppWidth = 0;
         displayInfo.largestNominalAppHeight = 0;
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh, legacyConfig);
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw, legacyConfig);
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh, legacyConfig);
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw, legacyConfig);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh, overrideConfig);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw, overrideConfig);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh,
+                overrideConfig);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw,
+                overrideConfig);
 
         if (outConfig == null) {
             return;
@@ -2623,17 +2616,17 @@
     }
 
     private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh,
-            boolean legacyConfig) {
+            boolean overrideConfig) {
         final DisplayPolicy.DecorInsets.Info info = mDisplayPolicy.getDecorInsetsInfo(
                 rotation, dw, dh);
         final int w;
         final int h;
-        if (!legacyConfig) {
+        if (!overrideConfig) {
             w = info.mConfigFrame.width();
             h = info.mConfigFrame.height();
         } else {
-            w = info.mLegacyConfigFrame.width();
-            h = info.mLegacyConfigFrame.height();
+            w = info.mOverrideConfigFrame.width();
+            h = info.mOverrideConfigFrame.height();
         }
         if (w < displayInfo.smallestNominalAppWidth) {
             displayInfo.smallestNominalAppWidth = w;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index a5037ea..5e0d4f9 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1935,9 +1935,9 @@
             final Rect mConfigInsets = new Rect();
 
             /**
-             * Legacy value of mConfigInsets for app compatibility purpose.
+             * Override value of mConfigInsets for app compatibility purpose.
              */
-            final Rect mLegacyConfigInsets = new Rect();
+            final Rect mOverrideConfigInsets = new Rect();
 
             /** The display frame available after excluding {@link #mNonDecorInsets}. */
             final Rect mNonDecorFrame = new Rect();
@@ -1950,9 +1950,9 @@
             final Rect mConfigFrame = new Rect();
 
             /**
-             * Legacy value of mConfigFrame for app compatibility purpose.
+             * Override value of mConfigFrame for app compatibility purpose.
              */
-            final Rect mLegacyConfigFrame = new Rect();
+            final Rect mOverrideConfigFrame = new Rect();
 
             private boolean mNeedUpdate = true;
 
@@ -1968,22 +1968,22 @@
                         ? decor
                         : insetsState.calculateInsets(displayFrame, dc.mWmService.mConfigTypes,
                                 true /* ignoreVisibility */);
-                final Insets legacyConfigInsets = dc.mWmService.mConfigTypes
-                        == dc.mWmService.mLegacyConfigTypes
+                final Insets overrideConfigInsets = dc.mWmService.mConfigTypes
+                        == dc.mWmService.mOverrideConfigTypes
                         ? configInsets
                         : insetsState.calculateInsets(displayFrame,
-                                dc.mWmService.mLegacyConfigTypes, true /* ignoreVisibility */);
+                                dc.mWmService.mOverrideConfigTypes, true /* ignoreVisibility */);
                 mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom);
                 mConfigInsets.set(configInsets.left, configInsets.top, configInsets.right,
                         configInsets.bottom);
-                mLegacyConfigInsets.set(legacyConfigInsets.left, legacyConfigInsets.top,
-                        legacyConfigInsets.right, legacyConfigInsets.bottom);
+                mOverrideConfigInsets.set(overrideConfigInsets.left, overrideConfigInsets.top,
+                        overrideConfigInsets.right, overrideConfigInsets.bottom);
                 mNonDecorFrame.set(displayFrame);
                 mNonDecorFrame.inset(mNonDecorInsets);
                 mConfigFrame.set(displayFrame);
                 mConfigFrame.inset(mConfigInsets);
-                mLegacyConfigFrame.set(displayFrame);
-                mLegacyConfigFrame.inset(mLegacyConfigInsets);
+                mOverrideConfigFrame.set(displayFrame);
+                mOverrideConfigFrame.inset(mOverrideConfigInsets);
                 mNeedUpdate = false;
                 return insetsState;
             }
@@ -1991,10 +1991,10 @@
             void set(Info other) {
                 mNonDecorInsets.set(other.mNonDecorInsets);
                 mConfigInsets.set(other.mConfigInsets);
-                mLegacyConfigInsets.set(other.mLegacyConfigInsets);
+                mOverrideConfigInsets.set(other.mOverrideConfigInsets);
                 mNonDecorFrame.set(other.mNonDecorFrame);
                 mConfigFrame.set(other.mConfigFrame);
-                mLegacyConfigFrame.set(other.mLegacyConfigFrame);
+                mOverrideConfigFrame.set(other.mOverrideConfigFrame);
                 mNeedUpdate = false;
             }
 
@@ -2107,7 +2107,7 @@
         final InsetsState newInsetsState = newInfo.update(mDisplayContent, rotation, dw, dh);
         final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh);
         if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)
-                && newInfo.mLegacyConfigFrame.equals(currentInfo.mLegacyConfigFrame)) {
+                && newInfo.mOverrideConfigFrame.equals(currentInfo.mOverrideConfigFrame)) {
             // Even if the config frame is not changed in current rotation, it may change the
             // insets in other rotations if the frame of insets source is changed.
             final InsetsState currentInsetsState = mDisplayContent.mDisplayFrames.mInsetsState;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index bd1503f..129af90 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2427,7 +2427,7 @@
         if (!useLegacyInsetsForStableBounds) {
             intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets);
         } else {
-            intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mLegacyConfigInsets);
+            intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mOverrideConfigInsets);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 59bda54..65e1761 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -856,11 +856,6 @@
         result.setWallpaperTarget(wallpaperTarget);
     }
 
-    public void updateWallpaperTokens(boolean keyguardLocked) {
-        updateWallpaperTokens(mWallpaperTarget != null || mPrevWallpaperTarget != null,
-                keyguardLocked);
-    }
-
     /**
      * Change the visibility of the top wallpaper to {@param visibility} and hide all the others.
      */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8a68afb..ed88b5a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -241,6 +241,7 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.IntArray;
 import android.util.MergedConfiguration;
 import android.util.Pair;
 import android.util.Slog;
@@ -567,7 +568,7 @@
     /** Device default insets types shall be excluded from config app sizes. */
     final int mConfigTypes;
 
-    final int mLegacyConfigTypes;
+    final int mOverrideConfigTypes;
 
     final boolean mLimitedAlphaCompositing;
     final int mMaxUiWidth;
@@ -1106,6 +1107,14 @@
 
     @GuardedBy("mGlobalLock")
     final SensitiveContentPackages mSensitiveContentPackages = new SensitiveContentPackages();
+    /**
+     * UIDs for which a Toast has been shown to indicate
+     * {@link LocalService#addBlockScreenCaptureForApps(ArraySet) screen capture blocking}. This is
+     * used to ensure we don't keep re-showing the Toast every time the window becomes visible.
+     * UIDs are removed when the app is removed from the block list.
+     */
+    @GuardedBy("mGlobalLock")
+    private final IntArray mCaptureBlockedToastShownUids = new IntArray();
 
     /** Listener to notify activity manager about app transitions. */
     final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
@@ -1238,20 +1247,18 @@
         if (mFlags.mInsetsDecoupledConfiguration) {
             mDecorTypes = 0;
             mConfigTypes = 0;
-        } else if (isScreenSizeDecoupledFromStatusBarAndCutout) {
-            mDecorTypes = WindowInsets.Type.navigationBars();
-            mConfigTypes = WindowInsets.Type.navigationBars();
         } else {
             mDecorTypes = WindowInsets.Type.displayCutout() | WindowInsets.Type.navigationBars();
             mConfigTypes = WindowInsets.Type.displayCutout() | WindowInsets.Type.statusBars()
                     | WindowInsets.Type.navigationBars();
         }
-        if (isScreenSizeDecoupledFromStatusBarAndCutout) {
-            // Do not fallback to legacy value for enabled devices.
-            mLegacyConfigTypes = WindowInsets.Type.navigationBars();
+        if (isScreenSizeDecoupledFromStatusBarAndCutout && !mFlags.mInsetsDecoupledConfiguration) {
+            // If the global new behavior is not there, but the partial decouple flag is on.
+            mOverrideConfigTypes = 0;
         } else {
-            mLegacyConfigTypes = WindowInsets.Type.displayCutout() | WindowInsets.Type.statusBars()
-                    | WindowInsets.Type.navigationBars();
+            mOverrideConfigTypes =
+                    WindowInsets.Type.displayCutout() | WindowInsets.Type.statusBars()
+                            | WindowInsets.Type.navigationBars();
         }
 
         mLetterboxConfiguration = new LetterboxConfiguration(
@@ -8748,6 +8755,15 @@
                 if (modified) {
                     WindowManagerService.this.refreshScreenCaptureDisabled();
                 }
+                if (sensitiveContentImprovements()) {
+                    for (int i = 0; i < packageInfos.size(); i++) {
+                        int uid = packageInfos.valueAt(i).getUid();
+                        if (mCaptureBlockedToastShownUids.contains(uid)) {
+                            mCaptureBlockedToastShownUids.remove(
+                                    mCaptureBlockedToastShownUids.indexOf(uid));
+                        }
+                    }
+                }
             }
         }
 
@@ -8758,6 +8774,9 @@
                 if (modified) {
                     WindowManagerService.this.refreshScreenCaptureDisabled();
                 }
+                if (sensitiveContentImprovements()) {
+                    mCaptureBlockedToastShownUids.clear();
+                }
             }
         }
 
@@ -10159,9 +10178,13 @@
      * on sensitive content protections.
      */
     private void showToastIfBlockingScreenCapture(@NonNull WindowState w) {
-        // TODO(b/323580163): Check if already shown and update shown state.
-        if (mSensitiveContentPackages.shouldBlockScreenCaptureForApp(w.getOwningPackage(),
-                w.getOwningUid(), w.getWindowToken())) {
+        int uid = w.getOwningUid();
+        if (mCaptureBlockedToastShownUids.contains(uid)) {
+            return;
+        }
+        if (mSensitiveContentPackages.shouldBlockScreenCaptureForApp(w.getOwningPackage(), uid,
+                w.getWindowToken())) {
+            mCaptureBlockedToastShownUids.add(uid);
             mH.post(() -> {
                 Toast.makeText(mContext, Looper.getMainLooper(),
                                 mContext.getString(R.string.screen_not_shared_sensitive_content),
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index aac567c..9d8246d 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -110,8 +110,8 @@
     private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
 
-    private static final int MAX_RAPID_ACTIVITY_LAUNCH_COUNT = 500;
-    private static final long RAPID_ACTIVITY_LAUNCH_MS = 300;
+    private static final int MAX_RAPID_ACTIVITY_LAUNCH_COUNT = 50;
+    private static final long RAPID_ACTIVITY_LAUNCH_MS = 500;
     private static final long RESET_RAPID_ACTIVITY_LAUNCH_MS = 5 * RAPID_ACTIVITY_LAUNCH_MS;
 
     public static final int STOPPED_STATE_NOT_STOPPED = 0;
@@ -639,9 +639,15 @@
         }
 
         if (mRapidActivityLaunchCount > MAX_RAPID_ACTIVITY_LAUNCH_COUNT) {
-            Slog.w(TAG, "Killing " + mPid + " because of rapid activity launch");
-            r.getRootTask().moveTaskToBack(r.getTask());
-            mAtm.mH.post(() -> mAtm.mAmInternal.killProcess(mName, mUid, "rapidActivityLaunch"));
+            mRapidActivityLaunchCount = 0;
+            final Task task = r.getTask();
+            Slog.w(TAG, "Removing task " + task.mTaskId + " because of rapid activity launch");
+            mAtm.mH.post(() -> {
+                synchronized (mAtm.mGlobalLock) {
+                    task.removeImmediately("rapid-activity-launch");
+                }
+                mAtm.mAmInternal.killProcess(mName, mUid, "rapidActivityLaunch");
+            });
         }
     }
 
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index f5ba50d..bb46c44 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.credentials.ClearCredentialStateException;
 import android.credentials.ClearCredentialStateRequest;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.IClearCredentialStateCallback;
 import android.credentials.selection.ProviderData;
@@ -41,7 +42,7 @@
 public final class ClearRequestSession extends RequestSession<ClearCredentialStateRequest,
         IClearCredentialStateCallback, Void>
         implements ProviderSession.ProviderInternalCallback<Void> {
-    private static final String TAG = "GetRequestSession";
+    private static final String TAG = CredentialManager.TAG;
 
     public ClearRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
             Object lock, int userId, int callingUid,
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index cac42b1..3513cb5 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -50,7 +50,7 @@
 public final class CreateRequestSession extends RequestSession<CreateCredentialRequest,
         ICreateCredentialCallback, CreateCredentialResponse>
         implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> {
-    private static final String TAG = "CreateRequestSession";
+    private static final String TAG = CredentialManager.TAG;
     private final Set<ComponentName> mPrimaryProviders;
 
     CreateRequestSession(@NonNull Context context, RequestSession.SessionLifetime sessionCallback,
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 281fb1c..6ef1436 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -34,6 +34,7 @@
 import android.credentials.ClearCredentialStateRequest;
 import android.credentials.CreateCredentialException;
 import android.credentials.CreateCredentialRequest;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialOption;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCandidateCredentialsException;
@@ -92,7 +93,7 @@
         extends AbstractMasterSystemService<
         CredentialManagerService, CredentialManagerServiceImpl> {
 
-    private static final String TAG = "CredManSysService";
+    private static final String TAG = CredentialManager.TAG;
     private static final String PERMISSION_DENIED_ERROR = "permission_denied";
     private static final String PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR =
             "Caller is missing WRITE_SECURE_SETTINGS permission";
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
index 379800b..38ad5b6 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.service.credentials.CredentialProviderInfoFactory;
 import android.util.Slog;
@@ -36,7 +37,7 @@
  */
 public final class CredentialManagerServiceImpl extends
         AbstractPerUserSystemService<CredentialManagerServiceImpl, CredentialManagerService> {
-    private static final String TAG = "CredManSysServiceImpl";
+    private static final String TAG = CredentialManager.TAG;
 
     @GuardedBy("mLock")
     @NonNull
@@ -93,7 +94,10 @@
     public ProviderSession initiateProviderSessionForRequestLocked(
             RequestSession requestSession, List<String> requestOptions) {
         if (!requestOptions.isEmpty() && !isServiceCapableLocked(requestOptions)) {
-            Slog.i(TAG, "Service does not have the required capabilities");
+            if (mInfo != null) {
+                Slog.i(TAG, "Service does not have the required capabilities: "
+                        + mInfo.getComponentName());
+            }
             return null;
         }
         if (mInfo == null) {
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 24f6697..bfa2d61 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -48,7 +48,6 @@
 
 /** Initiates the Credential Manager UI and receives results. */
 public class CredentialManagerUi {
-    private static final String TAG = "CredentialManagerUi";
     @NonNull
     private final CredentialManagerUiCallback mCallbacks;
     @NonNull
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index fd2a9a2..69d32a0 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.credentials.Constants;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCandidateCredentialsException;
 import android.credentials.GetCandidateCredentialsResponse;
@@ -54,7 +55,7 @@
 public class GetCandidateRequestSession extends RequestSession<GetCredentialRequest,
         IGetCandidateCredentialsCallback, GetCandidateCredentialsResponse>
         implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
-    private static final String TAG = "GetCandidateRequestSession";
+    private static final String TAG = CredentialManager.TAG;
 
     private static final String SESSION_ID_KEY = "autofill_session_id";
     private static final String REQUEST_ID_KEY = "autofill_request_id";
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index d55d8ef..c26229b 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialOption;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCredentialException;
@@ -48,7 +49,7 @@
 public class GetRequestSession extends RequestSession<GetCredentialRequest,
         IGetCredentialCallback, GetCredentialResponse>
         implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
-    private static final String TAG = "GetRequestSession";
+    private static final String TAG = CredentialManager.TAG;
 
     public GetRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
             Object lock, int userId, int callingUid,
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index 16bf1778..ac4aac6 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.credentials.CredentialManager;
 import android.util.Slog;
 
 import com.android.internal.util.FrameworkStatsLog;
@@ -44,7 +45,7 @@
 public class MetricUtilities {
     private static final boolean LOG_FLAG = true;
 
-    private static final String TAG = "MetricUtilities";
+    private static final String TAG = CredentialManager.TAG;
     public static final String USER_CANCELED_SUBSTRING = "TYPE_USER_CANCELED";
     public static final int MIN_EMIT_WAIT_TIME_MS = 10;
 
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index e4b5c77..f6b107b 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -21,6 +21,7 @@
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialOption;
 import android.credentials.GetCredentialRequest;
 import android.credentials.IGetCredentialCallback;
@@ -44,7 +45,7 @@
  * responses from providers, and the UX app, and updates the provider(s) state.
  */
 public class PrepareGetRequestSession extends GetRequestSession {
-    private static final String TAG = "PrepareGetRequestSession";
+    private static final String TAG = CredentialManager.TAG;
 
     private final IPrepareGetCredentialCallback mPrepareGetCredentialCallback;
 
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index 6a1b1db7..6759dbb 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -20,6 +20,7 @@
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.credentials.ClearCredentialStateException;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.selection.ProviderData;
 import android.credentials.selection.ProviderPendingIntentResponse;
@@ -37,7 +38,7 @@
         Void>
         implements
         RemoteCredentialService.ProviderCallbacks<Void> {
-    private static final String TAG = "ProviderClearSession";
+    private static final String TAG = CredentialManager.TAG;
 
     private ClearCredentialStateException mProviderException;
 
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 6361aeb..bee7f6c 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.credentials.CreateCredentialException;
 import android.credentials.CreateCredentialResponse;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.selection.CreateCredentialProviderData;
 import android.credentials.selection.Entry;
@@ -51,7 +52,7 @@
  */
 public final class ProviderCreateSession extends ProviderSession<
         BeginCreateCredentialRequest, BeginCreateCredentialResponse> {
-    private static final String TAG = "ProviderCreateSession";
+    private static final String TAG = CredentialManager.TAG;
 
     // Key to be used as an entry key for a save entry
     public static final String SAVE_ENTRY_KEY = "save_entry_key";
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index c5f2921..e18ef2b 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -22,6 +22,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialOption;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCredentialException;
@@ -61,7 +62,7 @@
         BeginGetCredentialResponse>
         implements
         RemoteCredentialService.ProviderCallbacks<BeginGetCredentialResponse> {
-    private static final String TAG = "ProviderGetSession";
+    private static final String TAG = CredentialManager.TAG;
     // Key to be used as the entry key for an action entry
     public static final String ACTION_ENTRY_KEY = "action_key";
     // Key to be used as the entry key for the authentication entry
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index f162916..83f9c24 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -22,6 +22,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialOption;
 import android.credentials.GetCredentialException;
 import android.credentials.GetCredentialResponse;
@@ -58,7 +59,7 @@
 public class ProviderRegistryGetSession extends ProviderSession<CredentialOption,
         Set<CredentialDescriptionRegistry.FilterResult>> {
 
-    private static final String TAG = "ProviderRegistryGetSession";
+    private static final String TAG = CredentialManager.TAG;
     @VisibleForTesting
     static final String CREDENTIAL_ENTRY_KEY = "credential_key";
 
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index dfc08f0..8f0ae90 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -24,6 +24,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.credentials.Credential;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.selection.ProviderData;
 import android.credentials.selection.ProviderPendingIntentResponse;
@@ -44,7 +45,7 @@
 public abstract class ProviderSession<T, R>
         implements RemoteCredentialService.ProviderCallbacks<R> {
 
-    private static final String TAG = "ProviderSession";
+    private static final String TAG = CredentialManager.TAG;
 
     @NonNull
     protected final Context mContext;
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index 4bcf8be..c361406 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.credentials.ClearCredentialStateException;
 import android.credentials.CreateCredentialException;
+import android.credentials.CredentialManager;
 import android.credentials.GetCredentialException;
 import android.os.Binder;
 import android.os.Handler;
@@ -58,7 +59,7 @@
  */
 public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialProviderService> {
 
-    private static final String TAG = "RemoteCredentialService";
+    private static final String TAG = CredentialManager.TAG;
     /** Timeout for a single request. */
     private static final long TIMEOUT_REQUEST_MILLIS = 3 * DateUtils.SECOND_IN_MILLIS;
     /** Timeout to unbind after the task queue is empty. */
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index a5b9aa6..054ba2b 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.credentials.CredentialManager;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.flags.Flags;
 import android.credentials.selection.ProviderData;
@@ -56,7 +57,7 @@
  * every time a new response type is expected from the providers.
  */
 abstract class RequestSession<T, U, V> implements CredentialManagerUi.CredentialManagerUiCallback {
-    private static final String TAG = "RequestSession";
+    private static final String TAG = CredentialManager.TAG;
 
     public interface SessionLifetime {
         /** Called when the user makes a selection. */
diff --git a/services/devicepolicy/TEST_MAPPING b/services/devicepolicy/TEST_MAPPING
index 0d5534b..b8cb4a9 100644
--- a/services/devicepolicy/TEST_MAPPING
+++ b/services/devicepolicy/TEST_MAPPING
@@ -26,5 +26,12 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    {
+      // TODO(b/332974906): Promote in presubmit presubmit-devicepolicy.
+      "name": "CtsDevicePolicyManagerTestCases_NoFlakes_NoLarge",
+      "name": "CtsDevicePolicyManagerTestCases_ParentProfileApiDisabled"
+    }
   ]
 }
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index 854bc0f..4b578af 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -1,5 +1,4 @@
 package: "android.server"
-container: "system"
 
 flag {
      namespace: "system_performance"
diff --git a/services/proguard.flags b/services/proguard.flags
index a01e7dc..f84eff7 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -33,12 +33,6 @@
 -keep,allowoptimization,allowaccessmodification class * extends com.android.server.SystemService {
   public <methods>;
 }
--keep,allowoptimization,allowaccessmodification class * extends com.android.server.devicepolicy.BaseIDevicePolicyManager {
-  public <init>(...);
-}
--keep,allowoptimization,allowaccessmodification class com.android.server.wallpaper.WallpaperManagerService {
-  public <init>(...);
-}
 
 # Accessed from com.android.compos APEX
 -keep,allowoptimization,allowaccessmodification class com.android.internal.art.ArtStatsLog {
@@ -68,13 +62,6 @@
 -keep public class android.hidl.manager.** { *; }
 -keep public class com.android.server.wm.WindowManagerInternal { *; }
 
-# Notification extractors
-# TODO(b/210510433): Revisit and consider generating from frameworks/base/core/res/res/values/config.xml.
--keep,allowoptimization,allowaccessmodification public class com.android.server.notification.** implements com.android.server.notification.NotificationSignalExtractor
-
-# OEM provided DisplayAreaPolicy.Provider defined in frameworks/base/core/res/res/values/config.xml.
--keep,allowoptimization,allowaccessmodification class com.android.server.wm.** implements com.android.server.wm.DisplayAreaPolicy$Provider
-
 # JNI keep rules
 # The global keep rule for native methods allows stripping of such methods if they're unreferenced
 # in Java. However, because system_server explicitly registers these methods from native code,
@@ -118,9 +105,6 @@
 
 # Miscellaneous reflection keep rules
 # TODO(b/210510433): Revisit and fix with @Keep.
--keep,allowoptimization,allowaccessmodification class com.android.server.usage.AppStandbyController {
-  public <init>(...);
-}
 -keep,allowoptimization,allowaccessmodification class android.hardware.usb.gadget.** { *; }
 
 # Needed when optimizations enabled
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
index ad4d91f..6d89e80 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
@@ -27,6 +27,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Objects;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DisplayBrightnessStateTest {
@@ -101,7 +103,9 @@
                 .append("\n    customAnimationRate:")
                 .append(displayBrightnessState.getCustomAnimationRate())
                 .append("\n    shouldUpdateScreenBrightnessSetting:")
-                .append(displayBrightnessState.shouldUpdateScreenBrightnessSetting());
+                .append(displayBrightnessState.shouldUpdateScreenBrightnessSetting())
+                .append("\n    mBrightnessEvent:")
+                .append(Objects.toString(displayBrightnessState.getBrightnessEvent(), "null"));
         return sb.toString();
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index b7fa7ea..eea94a4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -960,6 +960,9 @@
         final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
                 VIRTUAL_DISPLAY_NAME, width, height, dpi);
         builder.setUniqueId(uniqueId);
+        builder.setFlags(VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
+        when(mContext.checkCallingPermission(CAPTURE_VIDEO_OUTPUT))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
         final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
                 mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
         verify(mMockProjectionService, never()).setContentRecordingSession(any(),
@@ -972,6 +975,7 @@
                 VIRTUAL_DISPLAY_NAME, width, height, dpi).setUniqueId(uniqueId2);
         builder2.setUniqueId(uniqueId2);
         builder2.setDisplayIdToMirror(firstDisplayId);
+        builder2.setFlags(VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
         final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
                 mMockAppToken2 /* callback */, null /* projection */,
                 PACKAGE_NAME);
@@ -2448,8 +2452,9 @@
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
         assertThat(display.isEnabledLocked()).isFalse();
+        // TODO(b/332711269) make sure only one DISPLAY_GROUP_EVENT_ADDED sent.
         assertThat(callback.receivedEvents()).containsExactly(DISPLAY_GROUP_EVENT_ADDED,
-                EVENT_DISPLAY_CONNECTED).inOrder();
+                DISPLAY_GROUP_EVENT_ADDED, EVENT_DISPLAY_CONNECTED).inOrder();
     }
 
     @Test
@@ -2835,6 +2840,7 @@
 
         float brightness1 = 0.3f;
         float brightness2 = 0.45f;
+        waitForIdleHandler(mPowerHandler);
 
         int userId1 = 123;
         int userId2 = 456;
@@ -2844,8 +2850,8 @@
         userInfo2.id = userId2;
         when(mUserManager.getUserSerialNumber(userId1)).thenReturn(12345);
         when(mUserManager.getUserSerialNumber(userId2)).thenReturn(45678);
-        final SystemService.TargetUser from = new SystemService.TargetUser(userInfo1);
-        final SystemService.TargetUser to = new SystemService.TargetUser(userInfo2);
+        final SystemService.TargetUser user1 = new SystemService.TargetUser(userInfo1);
+        final SystemService.TargetUser user2 = new SystemService.TargetUser(userInfo2);
 
         // The same brightness will be restored for a user only if auto-brightness is off,
         // otherwise the current lux will be used to determine the brightness.
@@ -2853,20 +2859,20 @@
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
                 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
 
-        displayManager.onUserSwitching(to, from);
+        displayManager.onUserSwitching(/* from= */ user2, /* to= */ user1);
         waitForIdleHandler(mPowerHandler);
         displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, brightness1);
-        displayManager.onUserSwitching(from, to);
+        displayManager.onUserSwitching(/* from= */ user1, /* to= */ user2);
         waitForIdleHandler(mPowerHandler);
         displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, brightness2);
 
-        displayManager.onUserSwitching(to, from);
+        displayManager.onUserSwitching(/* from= */ user2, /* to= */ user1);
         waitForIdleHandler(mPowerHandler);
         assertEquals(brightness1,
                 displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
                 FLOAT_TOLERANCE);
 
-        displayManager.onUserSwitching(from, to);
+        displayManager.onUserSwitching(/* from= */ user1, /* to= */ user2);
         waitForIdleHandler(mPowerHandler);
         assertEquals(brightness2,
                 displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
diff --git a/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java b/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java
index 1a71e77..ea08be4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java
@@ -317,7 +317,8 @@
                 mDisplayEventCaptor.capture());
         assertThat(mLogicalDisplayCaptor.getValue()).isEqualTo(mMockedLogicalDisplay);
         assertThat(mDisplayEventCaptor.getValue()).isEqualTo(EVENT_DISPLAY_CONNECTED);
-        verify(mMockedLogicalDisplay).setEnabledLocked(false);
+        verify(mMockedLogicalDisplayMapper).setDisplayEnabledLocked(eq(mMockedLogicalDisplay),
+                eq(false));
         clearInvocations(mMockedLogicalDisplayMapper);
         clearInvocations(mMockedLogicalDisplay);
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index 6ed8238..1ae4099 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -111,8 +111,7 @@
         DisplayBrightnessStrategy displayBrightnessStrategy = mock(DisplayBrightnessStrategy.class);
         int targetDisplayState = Display.STATE_DOZE;
         when(mDisplayBrightnessStrategySelector.selectStrategy(
-                eq(new StrategySelectionRequest(displayPowerRequest, targetDisplayState))))
-                .thenReturn(displayBrightnessStrategy);
+                any(StrategySelectionRequest.class))).thenReturn(displayBrightnessStrategy);
         mDisplayBrightnessController.updateBrightness(displayPowerRequest, targetDisplayState);
         verify(displayBrightnessStrategy).updateBrightness(displayPowerRequest);
         assertEquals(mDisplayBrightnessController.getCurrentDisplayBrightnessStrategy(),
@@ -164,6 +163,7 @@
         // No brightness is set if the pending brightness is invalid
         mDisplayBrightnessController.setPendingScreenBrightness(Float.NaN);
         assertFalse(mDisplayBrightnessController.updateUserSetScreenBrightness());
+        assertFalse(mDisplayBrightnessController.getIsUserSetScreenBrightnessUpdated());
 
         // user set brightness is not set if the current and the pending brightness are same.
         float currentBrightness = 0.4f;
@@ -175,6 +175,7 @@
         mDisplayBrightnessController.setPendingScreenBrightness(currentBrightness);
         mDisplayBrightnessController.setTemporaryBrightness(currentBrightness);
         assertFalse(mDisplayBrightnessController.updateUserSetScreenBrightness());
+        assertFalse(mDisplayBrightnessController.getIsUserSetScreenBrightnessUpdated());
         verify(temporaryBrightnessStrategy).setTemporaryScreenBrightness(
                 PowerManager.BRIGHTNESS_INVALID_FLOAT);
         assertEquals(mDisplayBrightnessController.getPendingScreenBrightness(),
@@ -188,6 +189,7 @@
         mDisplayBrightnessController.setPendingScreenBrightness(pendingScreenBrightness);
         mDisplayBrightnessController.setTemporaryBrightness(temporaryScreenBrightness);
         assertTrue(mDisplayBrightnessController.updateUserSetScreenBrightness());
+        assertTrue(mDisplayBrightnessController.getIsUserSetScreenBrightnessUpdated());
         assertEquals(mDisplayBrightnessController.getCurrentBrightness(),
                 pendingScreenBrightness, /* delta= */ 0.0f);
         assertEquals(mDisplayBrightnessController.getLastUserSetScreenBrightness(),
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index 4c9dd58..b8858cc 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
@@ -40,6 +41,7 @@
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
 import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
+import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2;
 import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
 import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
@@ -80,6 +82,8 @@
     @Mock
     private AutomaticBrightnessStrategy mAutomaticBrightnessStrategy;
     @Mock
+    private AutomaticBrightnessStrategy2 mAutomaticBrightnessStrategy2;
+    @Mock
     private OffloadBrightnessStrategy mOffloadBrightnessStrategy;
     @Mock
     private Resources mResources;
@@ -126,12 +130,18 @@
                 }
 
                 @Override
-                AutomaticBrightnessStrategy getAutomaticBrightnessStrategy(Context context,
+                AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context,
                         int displayId) {
                     return mAutomaticBrightnessStrategy;
                 }
 
                 @Override
+                AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy2(Context context,
+                        int displayId) {
+                    return mAutomaticBrightnessStrategy2;
+                }
+
+                @Override
                 OffloadBrightnessStrategy getOffloadBrightnessStrategy() {
                     return mOffloadBrightnessStrategy;
                 }
@@ -162,7 +172,8 @@
         when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
                 DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE,
+                                0.1f, false)),
                 mDozeBrightnessModeStrategy);
     }
 
@@ -175,7 +186,8 @@
         when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
                 DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
         assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE)),
+                new StrategySelectionRequest(displayPowerRequest, Display.STATE_DOZE,
+                        0.1f, false)),
                 mDozeBrightnessModeStrategy);
     }
 
@@ -184,7 +196,8 @@
         DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
                 DisplayManagerInternal.DisplayPowerRequest.class);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_OFF)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_OFF,
+                                0.1f, false)),
                 mScreenOffBrightnessModeStrategy);
     }
 
@@ -195,7 +208,8 @@
         displayPowerRequest.screenBrightnessOverride = 0.4f;
         when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
                 mOverrideBrightnessStrategy);
     }
 
@@ -207,7 +221,8 @@
         when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
         when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(0.3f);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
                 mTemporaryBrightnessStrategy);
     }
 
@@ -220,7 +235,8 @@
         displayPowerRequest.screenBrightnessOverride = Float.NaN;
         when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
                 mBoostBrightnessStrategy);
     }
 
@@ -233,7 +249,8 @@
         when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
         when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(Float.NaN);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
                 mInvalidBrightnessStrategy);
     }
 
@@ -243,7 +260,8 @@
                 DisplayManagerInternal.DisplayPowerRequest.class);
         when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(0.3f);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
                 mFollowerBrightnessStrategy);
     }
 
@@ -257,14 +275,39 @@
         displayPowerRequest.screenBrightnessOverride = Float.NaN;
         when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
         when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
-        when(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()).thenReturn(true);
+        when(mAutomaticBrightnessStrategy2.shouldUseAutoBrightness()).thenReturn(true);
         when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(0.3f);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON)),
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
                 mOffloadBrightnessStrategy);
     }
 
     @Test
+    public void selectStrategy_selectsAutomaticStrategyWhenValid() {
+        when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
+        mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
+                mInjector, DISPLAY_ID, mDisplayManagerFlags);
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        displayPowerRequest.screenBrightnessOverride = Float.NaN;
+        when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
+        when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
+        when(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()).thenReturn(true);
+        when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(true);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
+                mAutomaticBrightnessStrategy);
+        verifyZeroInteractions(mOffloadBrightnessStrategy);
+        verify(mAutomaticBrightnessStrategy).setAutoBrightnessState(Display.STATE_ON,
+                false, BrightnessReason.REASON_UNKNOWN,
+                DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT, 0.1f, false);
+
+    }
+
+    @Test
     public void selectStrategyDoesNotSelectOffloadStrategyWhenFeatureFlagDisabled() {
         when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(false);
         mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
@@ -277,7 +320,8 @@
         when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(0.3f);
         assertNotEquals(mOffloadBrightnessStrategy,
                 mDisplayBrightnessStrategySelector.selectStrategy(
-                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON)));
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)));
     }
 
     @Test
@@ -290,10 +334,13 @@
         when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(0.3f);
 
         mDisplayBrightnessStrategySelector.selectStrategy(
-                new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON));
+                new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                        0.1f, false));
 
         StrategySelectionNotifyRequest strategySelectionNotifyRequest =
-                new StrategySelectionNotifyRequest(mFollowerBrightnessStrategy);
+                new StrategySelectionNotifyRequest(displayPowerRequest, Display.STATE_ON,
+                        mFollowerBrightnessStrategy, 0.1f,
+                        false, false);
         verify(mInvalidBrightnessStrategy).strategySelectionPostProcessor(
                 eq(strategySelectionNotifyRequest));
         verify(mScreenOffBrightnessModeStrategy).strategySelectionPostProcessor(
@@ -308,5 +355,22 @@
                 eq(strategySelectionNotifyRequest));
         verify(mTemporaryBrightnessStrategy).strategySelectionPostProcessor(
                 eq(strategySelectionNotifyRequest));
+        verify(mAutomaticBrightnessStrategy).strategySelectionPostProcessor(
+                eq(strategySelectionNotifyRequest));
+    }
+
+    @Test
+    public void getAutomaticBrightnessStrategy_getsAutomaticStrategy2IfRefactoringFlagIsNotSet() {
+        assertEquals(mAutomaticBrightnessStrategy2,
+                mDisplayBrightnessStrategySelector.getAutomaticBrightnessStrategy());
+    }
+
+    @Test
+    public void getAutomaticBrightnessStrategy_getsAutomaticStrategyIfRefactoringFlagIsSet() {
+        when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
+        mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
+                mInjector, DISPLAY_ID, mDisplayManagerFlags);
+        assertEquals(mAutomaticBrightnessStrategy,
+                mDisplayBrightnessStrategySelector.getAutomaticBrightnessStrategy());
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2Test.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2Test.java
new file mode 100644
index 0000000..fd43720
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2Test.java
@@ -0,0 +1,415 @@
+/*
+ * 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.server.display.brightness.strategy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+import android.view.Display;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
+import com.android.server.display.AutomaticBrightnessController;
+import com.android.server.display.brightness.BrightnessEvent;
+import com.android.server.display.brightness.BrightnessReason;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AutomaticBrightnessStrategy2Test {
+    private static final int DISPLAY_ID = 0;
+    @Rule
+    public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
+
+    @Mock
+    private AutomaticBrightnessController mAutomaticBrightnessController;
+
+    private BrightnessConfiguration mBrightnessConfiguration;
+    private float mDefaultScreenAutoBrightnessAdjustment;
+    private Context mContext;
+    private AutomaticBrightnessStrategy2 mAutomaticBrightnessStrategy;
+
+    @Before
+    public void before() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+        final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
+        when(mContext.getContentResolver()).thenReturn(resolver);
+        mDefaultScreenAutoBrightnessAdjustment = Settings.System.getFloat(
+                mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, Float.NaN);
+        Settings.System.putFloat(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.5f);
+        mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy2(mContext, DISPLAY_ID);
+
+        mBrightnessConfiguration = new BrightnessConfiguration.Builder(
+                new float[]{0f, 1f}, new float[]{0, PowerManager.BRIGHTNESS_ON}).build();
+        when(mAutomaticBrightnessController.hasUserDataPoints()).thenReturn(true);
+        mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
+                mAutomaticBrightnessController);
+        mAutomaticBrightnessStrategy.setBrightnessConfiguration(mBrightnessConfiguration,
+                true);
+    }
+
+    @After
+    public void after() {
+        Settings.System.putFloat(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, mDefaultScreenAutoBrightnessAdjustment);
+    }
+
+    @Test
+    public void testAutoBrightnessState_AutoBrightnessDisabled() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(false);
+        int targetDisplayState = Display.STATE_ON;
+        boolean allowAutoBrightnessWhileDozing = false;
+        int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        float lastUserSetBrightness = 0.2f;
+        boolean userSetBrightnessChanged = true;
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController)
+                .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
+                        mBrightnessConfiguration,
+                        lastUserSetBrightness,
+                        userSetBrightnessChanged, /* adjustment */ 0.5f,
+                        /* userChangedAutoBrightnessAdjustment= */ false, policy,
+                        targetDisplayState, /* shouldResetShortTermModel */ true);
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+    }
+
+    @Test
+    public void testAutoBrightnessState_DisplayIsOff() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        int targetDisplayState = Display.STATE_OFF;
+        boolean allowAutoBrightnessWhileDozing = false;
+        int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+        float lastUserSetBrightness = 0.2f;
+        boolean userSetBrightnessChanged = true;
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController)
+                .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+                        mBrightnessConfiguration,
+                        lastUserSetBrightness,
+                        userSetBrightnessChanged, /* adjustment */ 0.5f,
+                        /* userChangedAutoBrightnessAdjustment= */ false, policy,
+                        targetDisplayState, /* shouldResetShortTermModel */ true);
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+        assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+    }
+
+    @Test
+    public void testAutoBrightnessState_DisplayIsInDoze_ConfigDoesNotAllow() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        int targetDisplayState = Display.STATE_DOZE;
+        boolean allowAutoBrightnessWhileDozing = false;
+        int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+        float lastUserSetBrightness = 0.2f;
+        boolean userSetBrightnessChanged = true;
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController)
+                .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+                        mBrightnessConfiguration,
+                        lastUserSetBrightness,
+                        userSetBrightnessChanged, /* adjustment */ 0.5f,
+                        /* userChangedAutoBrightnessAdjustment= */ false, policy,
+                        targetDisplayState, /* shouldResetShortTermModel */ true);
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+        assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+    }
+
+    @Test
+    public void testAutoBrightnessState_BrightnessReasonIsOverride() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        int targetDisplayState = Display.STATE_ON;
+        boolean allowAutoBrightnessWhileDozing = false;
+        int brightnessReason = BrightnessReason.REASON_OVERRIDE;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        float lastUserSetBrightness = 0.2f;
+        boolean userSetBrightnessChanged = true;
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController)
+                .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED,
+                        mBrightnessConfiguration,
+                        lastUserSetBrightness,
+                        userSetBrightnessChanged, /* adjustment */ 0.5f,
+                        /* userChangedAutoBrightnessAdjustment= */ false, policy,
+                        targetDisplayState, /* shouldResetShortTermModel */ true);
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+    }
+
+    @Test
+    public void testAutoBrightnessState_DisplayIsInDoze_ConfigDoesAllow() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        int targetDisplayState = Display.STATE_DOZE;
+        boolean allowAutoBrightnessWhileDozing = true;
+        int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+        float lastUserSetBrightness = 0.2f;
+        boolean userSetBrightnessChanged = true;
+        Settings.System.putFloat(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.4f);
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController)
+                .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
+                        mBrightnessConfiguration,
+                        lastUserSetBrightness,
+                        userSetBrightnessChanged, /* adjustment */ 0.4f,
+                        /* userChangedAutoBrightnessAdjustment= */ true, policy,
+                        targetDisplayState, /* shouldResetShortTermModel */ true);
+        assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+    }
+
+    @Test
+    public void testAutoBrightnessState_DisplayIsOn() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        int targetDisplayState = Display.STATE_ON;
+        boolean allowAutoBrightnessWhileDozing = false;
+        int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+        float lastUserSetBrightness = 0.2f;
+        boolean userSetBrightnessChanged = true;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        float pendingBrightnessAdjustment = 0.1f;
+        Settings.System.putFloat(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingBrightnessAdjustment);
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController)
+                .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
+                        mBrightnessConfiguration,
+                        lastUserSetBrightness,
+                        userSetBrightnessChanged, pendingBrightnessAdjustment,
+                        /* userChangedAutoBrightnessAdjustment= */ true, policy, targetDisplayState,
+                        /* shouldResetShortTermModel */ true);
+        assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled());
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff());
+    }
+
+    @Test
+    public void accommodateUserBrightnessChangesWorksAsExpected() {
+        // Verify the state if automaticBrightnessController is configured.
+        assertFalse(mAutomaticBrightnessStrategy.isShortTermModelActive());
+        boolean userSetBrightnessChanged = true;
+        float lastUserSetScreenBrightness = 0.2f;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        int targetDisplayState = Display.STATE_ON;
+        BrightnessConfiguration brightnessConfiguration = new BrightnessConfiguration.Builder(
+                new float[]{0f, 1f}, new float[]{0, PowerManager.BRIGHTNESS_ON}).build();
+        int autoBrightnessState = AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
+        float temporaryAutoBrightnessAdjustments = 0.4f;
+        mAutomaticBrightnessStrategy.setShouldResetShortTermModel(true);
+        setTemporaryAutoBrightnessAdjustment(temporaryAutoBrightnessAdjustments);
+        mAutomaticBrightnessStrategy.accommodateUserBrightnessChanges(userSetBrightnessChanged,
+                lastUserSetScreenBrightness, policy, targetDisplayState, brightnessConfiguration,
+                autoBrightnessState);
+        verify(mAutomaticBrightnessController).configure(autoBrightnessState,
+                brightnessConfiguration,
+                lastUserSetScreenBrightness,
+                userSetBrightnessChanged, temporaryAutoBrightnessAdjustments,
+                /* userChangedAutoBrightnessAdjustment= */ false, policy, targetDisplayState,
+                /* shouldResetShortTermModel= */ true);
+        assertTrue(mAutomaticBrightnessStrategy.isTemporaryAutoBrightnessAdjustmentApplied());
+        assertFalse(mAutomaticBrightnessStrategy.shouldResetShortTermModel());
+        assertTrue(mAutomaticBrightnessStrategy.isShortTermModelActive());
+        // Verify the state when automaticBrightnessController is not configured
+        setTemporaryAutoBrightnessAdjustment(Float.NaN);
+        mAutomaticBrightnessStrategy.setAutomaticBrightnessController(null);
+        mAutomaticBrightnessStrategy.setShouldResetShortTermModel(true);
+        mAutomaticBrightnessStrategy.accommodateUserBrightnessChanges(userSetBrightnessChanged,
+                lastUserSetScreenBrightness, policy, targetDisplayState, brightnessConfiguration,
+                autoBrightnessState);
+        assertFalse(mAutomaticBrightnessStrategy.isTemporaryAutoBrightnessAdjustmentApplied());
+        assertTrue(mAutomaticBrightnessStrategy.shouldResetShortTermModel());
+        assertFalse(mAutomaticBrightnessStrategy.isShortTermModelActive());
+    }
+
+    @Test
+    public void adjustAutomaticBrightnessStateIfValid() throws Settings.SettingNotFoundException {
+        float brightnessState = 0.3f;
+        float autoBrightnessAdjustment = 0.2f;
+        when(mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment()).thenReturn(
+                autoBrightnessAdjustment);
+        mAutomaticBrightnessStrategy.adjustAutomaticBrightnessStateIfValid(brightnessState);
+        assertEquals(autoBrightnessAdjustment,
+                mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f);
+        assertEquals(autoBrightnessAdjustment, Settings.System.getFloatForUser(
+                mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
+                UserHandle.USER_CURRENT), 0.0f);
+        assertEquals(BrightnessReason.ADJUSTMENT_AUTO,
+                mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags());
+        float invalidBrightness = -0.5f;
+        mAutomaticBrightnessStrategy
+                .adjustAutomaticBrightnessStateIfValid(invalidBrightness);
+        assertEquals(autoBrightnessAdjustment,
+                mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f);
+        assertEquals(0,
+                mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags());
+    }
+
+    @Test
+    public void updatePendingAutoBrightnessAdjustments() {
+        // Verify the state when the pendingAutoBrightnessAdjustments are not present
+        setPendingAutoBrightnessAdjustment(Float.NaN);
+        assertFalse(mAutomaticBrightnessStrategy.processPendingAutoBrightnessAdjustments());
+        assertFalse(mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged());
+        // Verify the state when the pendingAutoBrightnessAdjustments are present, but
+        // pendingAutoBrightnessAdjustments and autoBrightnessAdjustments are the same
+        float autoBrightnessAdjustment = 0.3f;
+        setPendingAutoBrightnessAdjustment(autoBrightnessAdjustment);
+        setAutoBrightnessAdjustment(autoBrightnessAdjustment);
+        assertFalse(mAutomaticBrightnessStrategy.processPendingAutoBrightnessAdjustments());
+        assertFalse(mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged());
+        assertEquals(Float.NaN, mAutomaticBrightnessStrategy.getPendingAutoBrightnessAdjustment(),
+                0.0f);
+        // Verify the state when the pendingAutoBrightnessAdjustments are present, and
+        // pendingAutoBrightnessAdjustments and autoBrightnessAdjustments are not the same
+        float pendingAutoBrightnessAdjustment = 0.2f;
+        setPendingAutoBrightnessAdjustment(pendingAutoBrightnessAdjustment);
+        setTemporaryAutoBrightnessAdjustment(0.1f);
+        assertTrue(mAutomaticBrightnessStrategy.processPendingAutoBrightnessAdjustments());
+        assertTrue(mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged());
+        assertEquals(pendingAutoBrightnessAdjustment,
+                mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f);
+        assertEquals(Float.NaN, mAutomaticBrightnessStrategy.getPendingAutoBrightnessAdjustment(),
+                0.0f);
+        assertEquals(Float.NaN, mAutomaticBrightnessStrategy.getTemporaryAutoBrightnessAdjustment(),
+                0.0f);
+    }
+
+    @Test
+    public void setAutomaticBrightnessWorksAsExpected() {
+        float automaticScreenBrightness = 0.3f;
+        AutomaticBrightnessController automaticBrightnessController = mock(
+                AutomaticBrightnessController.class);
+        when(automaticBrightnessController.getAutomaticScreenBrightness(any(BrightnessEvent.class)))
+                .thenReturn(automaticScreenBrightness);
+        when(automaticBrightnessController.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                any(BrightnessEvent.class)))
+                .thenReturn(automaticScreenBrightness);
+        mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
+                automaticBrightnessController);
+        assertEquals(automaticScreenBrightness,
+                mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
+                        new BrightnessEvent(DISPLAY_ID)), 0.0f);
+        assertEquals(automaticScreenBrightness,
+                mAutomaticBrightnessStrategy.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                        new BrightnessEvent(DISPLAY_ID)), 0.0f);
+    }
+
+    @Test
+    public void shouldUseAutoBrightness() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        assertTrue(mAutomaticBrightnessStrategy.shouldUseAutoBrightness());
+    }
+
+    @Test
+    public void setPendingAutoBrightnessAdjustments() throws Settings.SettingNotFoundException {
+        float pendingAutoBrightnessAdjustments = 0.3f;
+        setPendingAutoBrightnessAdjustment(pendingAutoBrightnessAdjustments);
+        assertEquals(pendingAutoBrightnessAdjustments,
+                mAutomaticBrightnessStrategy.getPendingAutoBrightnessAdjustment(), 0.0f);
+        assertEquals(pendingAutoBrightnessAdjustments, Settings.System.getFloatForUser(
+                mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
+                UserHandle.USER_CURRENT), 0.0f);
+    }
+
+    @Test
+    public void setTemporaryAutoBrightnessAdjustment() {
+        float temporaryAutoBrightnessAdjustment = 0.3f;
+        mAutomaticBrightnessStrategy.setTemporaryAutoBrightnessAdjustment(
+                temporaryAutoBrightnessAdjustment);
+        assertEquals(temporaryAutoBrightnessAdjustment,
+                mAutomaticBrightnessStrategy.getTemporaryAutoBrightnessAdjustment(), 0.0f);
+    }
+
+    @Test
+    public void setAutoBrightnessApplied() {
+        mAutomaticBrightnessStrategy.setAutoBrightnessApplied(true);
+        assertTrue(mAutomaticBrightnessStrategy.hasAppliedAutoBrightness());
+    }
+
+    @Test
+    public void testVerifyNoAutoBrightnessAdjustmentsArePopulatedForNonDefaultDisplay() {
+        int newDisplayId = 1;
+        mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy2(mContext, newDisplayId);
+        mAutomaticBrightnessStrategy.putAutoBrightnessAdjustmentSetting(0.3f);
+        assertEquals(0.5f, mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(),
+                0.0f);
+    }
+
+    private void setPendingAutoBrightnessAdjustment(float pendingAutoBrightnessAdjustment) {
+        Settings.System.putFloat(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingAutoBrightnessAdjustment);
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+    }
+
+    private void setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment) {
+        mAutomaticBrightnessStrategy.setTemporaryAutoBrightnessAdjustment(
+                temporaryAutoBrightnessAdjustment);
+    }
+
+    private void setAutoBrightnessAdjustment(float autoBrightnessAdjustment) {
+        mAutomaticBrightnessStrategy.putAutoBrightnessAdjustmentSetting(autoBrightnessAdjustment);
+    }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 4e55270..6e163ca 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -398,6 +398,34 @@
                 0.0f);
     }
 
+    @Test
+    public void isAutoBrightnessValid_returnsFalseWhenAutoBrightnessIsDisabled() {
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessValid());
+    }
+
+    @Test
+    public void isAutoBrightnessValid_returnsFalseWhenBrightnessIsInvalid() {
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON, true,
+                BrightnessReason.REASON_UNKNOWN,
+                DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT, 0.1f,
+                false);
+        when(mAutomaticBrightnessController.getAutomaticScreenBrightness(null))
+                .thenReturn(Float.NaN);
+        assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessValid());
+    }
+
+    @Test
+    public void isAutoBrightnessValid_returnsTrueWhenBrightnessIsValid() {
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON, true,
+                BrightnessReason.REASON_UNKNOWN,
+                DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT, 0.1f,
+                false);
+        when(mAutomaticBrightnessController.getAutomaticScreenBrightness(null))
+                .thenReturn(0.2f);
+        assertTrue(mAutomaticBrightnessStrategy.isAutoBrightnessValid());
+    }
+
     private void setPendingAutoBrightnessAdjustment(float pendingAutoBrightnessAdjustment) {
         Settings.System.putFloat(mContext.getContentResolver(),
                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingAutoBrightnessAdjustment);
diff --git a/services/tests/mockingservicestests/src/com/android/server/OWNERS b/services/tests/mockingservicestests/src/com/android/server/OWNERS
index 0eb8639..dc5cb8d6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/OWNERS
@@ -3,3 +3,5 @@
 per-file *DeviceIdleController* = file:/apex/jobscheduler/OWNERS
 per-file SensitiveContentProtectionManagerService* = file:/core/java/android/permission/OWNERS
 per-file RescuePartyTest.java = file:/packages/CrashRecovery/OWNERS
+per-file *Storage* = file:/core/java/android/os/storage/OWNERS
+
diff --git a/services/tests/mockingservicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/StorageManagerServiceTest.java
new file mode 100644
index 0000000..2e4b97e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.server;
+
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.multiuser.Flags;
+import android.os.UserManager;
+import android.os.storage.ICeStorageLockEventListener;
+import android.os.storage.StorageManagerInternal;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class StorageManagerServiceTest {
+
+    private final Context mRealContext = androidx.test.platform.app.InstrumentationRegistry
+            .getInstrumentation().getTargetContext();
+    private StorageManagerService mStorageManagerService;
+    private StorageManagerInternal mStorageManagerInternal;
+
+    private static final int TEST_USER_ID = 1001;
+
+    @Rule
+    public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
+            .spyStatic(UserManager.class)
+            .build();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    private static class TestStorageEventListener implements ICeStorageLockEventListener {
+
+        private int mExpectedUserId;
+
+        private TestStorageEventListener(int userId) {
+            mExpectedUserId = userId;
+        }
+
+        @Override
+        public void onStorageLocked(int userId) {
+            assertThat(userId).isEqualTo(mExpectedUserId);
+        }
+    }
+
+
+    @Before
+    public void setFixtures() {
+        // Called when WatchedUserStates is constructed
+        doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
+
+        mStorageManagerService = new StorageManagerService(mRealContext);
+        mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
+        assertWithMessage("LocalServices.getService(StorageManagerInternal.class)")
+                .that(mStorageManagerInternal).isNotNull();
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(StorageManagerInternal.class);
+    }
+
+    @Test
+    public void testRegisterLockEventListener() {
+        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+                Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE,
+                Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
+        CopyOnWriteArrayList<ICeStorageLockEventListener> storageLockEventListeners =
+                mStorageManagerService.getCeStorageEventCallbacks();
+        assertThat(storageLockEventListeners).isNotNull();
+        int registeredCallbackCount = storageLockEventListeners.size();
+        TestStorageEventListener testStorageEventListener =
+                new TestStorageEventListener(TEST_USER_ID);
+        mStorageManagerInternal.registerStorageLockEventListener(testStorageEventListener);
+        assertNumberOfStorageCallbackReceivers(registeredCallbackCount + 1);
+
+        mStorageManagerInternal.unregisterStorageLockEventListener(testStorageEventListener);
+        assertNumberOfStorageCallbackReceivers(registeredCallbackCount);
+    }
+
+    @Test
+    public void testDispatchCeStorageLockEvent() {
+        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+                Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE,
+                Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
+
+        assertThat(mStorageManagerService.getCeStorageEventCallbacks()).isNotNull();
+        int callbackReceiverSize = mStorageManagerService.getCeStorageEventCallbacks().size();
+        TestStorageEventListener testStorageEventListener =
+                spy(new TestStorageEventListener(TEST_USER_ID));
+
+        // Add testStorageEventListener to the list of storage callback listeners
+        mStorageManagerService.getCeStorageEventCallbacks().add(testStorageEventListener);
+        assertNumberOfStorageCallbackReceivers(callbackReceiverSize + 1);
+
+        mStorageManagerService.dispatchCeStorageLockedEvent(TEST_USER_ID);
+        verify(testStorageEventListener).onStorageLocked(eq(TEST_USER_ID));
+
+        // Remove testStorageEventListener from the list of storage callback listeners
+        mStorageManagerService.getCeStorageEventCallbacks().remove(testStorageEventListener);
+        assertNumberOfStorageCallbackReceivers(callbackReceiverSize);
+    }
+
+    private void assertNumberOfStorageCallbackReceivers(int callbackReceiverSize) {
+        assertThat(mStorageManagerService.getCeStorageEventCallbacks()).isNotNull();
+        assertThat(mStorageManagerService.getCeStorageEventCallbacks().size())
+                    .isEqualTo(callbackReceiverSize);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java
index 18dc114..7e17909 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+
 import android.annotation.NonNull;
 import android.app.backup.BackupHelper;
 import android.app.backup.BackupHelperWithLogger;
@@ -29,8 +31,6 @@
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.ArraySet;
 
-import static org.mockito.Mockito.when;
-
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -92,7 +92,8 @@
                         "people",
                         "app_locales",
                         "app_gender",
-                        "companion");
+                        "companion",
+                        "system_gender");
     }
 
     @Test
@@ -116,7 +117,8 @@
                         "people",
                         "app_locales",
                         "app_gender",
-                        "companion");
+                        "companion",
+                        "system_gender");
     }
 
     @Test
@@ -132,7 +134,9 @@
                         "notifications",
                         "permissions",
                         "app_locales",
-                        "companion");
+                        "companion",
+                        "app_gender",
+                        "system_gender");
     }
 
     @Test
@@ -152,7 +156,9 @@
                         "account_manager",
                         "usage_stats",
                         "shortcut_manager",
-                        "companion");
+                        "companion",
+                        "app_gender",
+                        "system_gender");
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 671472d..6df4907 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -1978,7 +1978,7 @@
     }
 
     @Test
-    public void testIsWithinQuotaLocked_UnderDuration_OverJobCountRateLimitWindow() {
+    public void testIsWithinQuotaLocked_UnderDuration_OverJobCount() {
         setDischarging();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW;
@@ -2021,7 +2021,7 @@
     }
 
     @Test
-    public void testIsWithinQuotaLocked_OverDuration_OverJobCountRateLimitWindow() {
+    public void testIsWithinQuotaLocked_OverDuration_OverJobCount() {
         setDischarging();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW;
@@ -2167,73 +2167,6 @@
     }
 
     @Test
-    public void testIsWithinQuotaLocked_UnderDuration_OverJobCountInWindow() {
-        setDischarging();
-
-        JobStatus jobRunning = createJobStatus(
-                "testIsWithinQuotaLocked_UnderDuration_OverJobCountInWindow", 1);
-        JobStatus jobPending = createJobStatus(
-                "testIsWithinQuotaLocked_UnderDuration_OverJobCountInWindow", 2);
-        setStandbyBucket(WORKING_INDEX, jobRunning, jobPending);
-
-        setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_WORKING, 10);
-
-        long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (HOUR_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 9), false);
-
-        final ExecutionStats stats;
-        synchronized (mQuotaController.mLock) {
-            stats = mQuotaController.getExecutionStatsLocked(
-                    SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX);
-            assertTrue(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(10, stats.jobCountLimit);
-            assertEquals(9, stats.bgJobCountInWindow);
-        }
-
-        when(mJobSchedulerService.isCurrentlyRunningLocked(jobRunning)).thenReturn(true);
-        when(mJobSchedulerService.isCurrentlyRunningLocked(jobPending)).thenReturn(false);
-
-        InOrder inOrder = inOrder(mJobSchedulerService);
-        trackJobs(jobRunning, jobPending);
-        // UID in the background.
-        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
-        // Start the job.
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.prepareForExecutionLocked(jobRunning);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        // Wait for some extra time to allow for job processing.
-        ArraySet<JobStatus> expected = new ArraySet<>();
-        expected.add(jobPending);
-        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
-                .onControllerStateChanged(eq(expected));
-
-        synchronized (mQuotaController.mLock) {
-            assertTrue(mQuotaController.isWithinQuotaLocked(jobRunning));
-            assertTrue(jobRunning.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
-            assertTrue(jobRunning.isReady());
-            assertFalse(mQuotaController.isWithinQuotaLocked(jobPending));
-            assertFalse(jobPending.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
-            assertFalse(jobPending.isReady());
-            assertEquals(10, stats.bgJobCountInWindow);
-        }
-
-        advanceElapsedClock(MINUTE_IN_MILLIS);
-        synchronized (mQuotaController.mLock) {
-            mQuotaController.maybeStopTrackingJobLocked(jobRunning, null);
-        }
-
-        synchronized (mQuotaController.mLock) {
-            assertFalse(mQuotaController
-                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
-            assertEquals(10, stats.bgJobCountInWindow);
-        }
-    }
-
-    @Test
     public void testIsWithinQuotaLocked_TimingSession() {
         setDischarging();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -4718,7 +4651,7 @@
         // Handler is told to check when the quota will be consumed, not when the initial
         // remaining time is over.
         verify(handler, atLeast(1)).sendMessageDelayed(
-                argThat(msg -> msg.what == QuotaController.MSG_REACHED_TIME_QUOTA),
+                argThat(msg -> msg.what == QuotaController.MSG_REACHED_QUOTA),
                 eq(10 * SECOND_IN_MILLIS));
         verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
 
@@ -6685,7 +6618,7 @@
         // Handler is told to check when the quota will be consumed, not when the initial
         // remaining time is over.
         verify(handler, atLeast(1)).sendMessageDelayed(
-                argThat(msg -> msg.what == QuotaController.MSG_REACHED_EJ_TIME_QUOTA),
+                argThat(msg -> msg.what == QuotaController.MSG_REACHED_EJ_QUOTA),
                 eq(10 * SECOND_IN_MILLIS));
         verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 759a974..79f1574 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -34,6 +34,7 @@
 
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -58,6 +59,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.util.Log;
@@ -139,7 +141,8 @@
             .mockStatic(Settings.Secure.class)
             .build();
 
-    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(
+            SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
 
     private final Object mPackagesLock = new Object();
     private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
@@ -584,10 +587,12 @@
     public void testAutoLockPrivateProfile() {
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
+        int mainUser = mUms.getMainUserId();
+        assumeTrue(mUms.canAddPrivateProfile(mainUser));
         UserManagerService mSpiedUms = spy(mUms);
         UserInfo privateProfileUser =
                 mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
-                        USER_TYPE_PROFILE_PRIVATE, 0, 0, null);
+                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);
         Mockito.doNothing().when(mSpiedUms).setQuietModeEnabledAsync(
                 eq(privateProfileUser.getUserHandle().getIdentifier()), eq(true), any(),
                 any());
@@ -604,10 +609,12 @@
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE);
+        int mainUser = mUms.getMainUserId();
+        assumeTrue(mUms.canAddPrivateProfile(mainUser));
         UserManagerService mSpiedUms = spy(mUms);
         UserInfo privateProfileUser =
                 mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
-                USER_TYPE_PROFILE_PRIVATE, 0, 0, null);
+                USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);
         mockAutoLockForPrivateSpace(Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK);
         Mockito.doNothing().when(mSpiedUms).setQuietModeEnabledAsync(
                 eq(privateProfileUser.getUserHandle().getIdentifier()), eq(true), any(),
@@ -625,6 +632,7 @@
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE);
+        assumeTrue(mUms.canAddPrivateProfile(0));
         UserManagerService mSpiedUms = spy(mUms);
         UserInfo privateProfileUser =
                 mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
@@ -644,10 +652,12 @@
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         mSetFlagsRule.disableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE);
+        int mainUser = mUms.getMainUserId();
+        assumeTrue(mUms.canAddPrivateProfile(mainUser));
         UserManagerService mSpiedUms = spy(mUms);
         UserInfo privateProfileUser =
                 mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
-                USER_TYPE_PROFILE_PRIVATE, 0, 0, null);
+                USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);
 
         mSpiedUms.tryAutoLockingPrivateSpaceOnKeyguardChanged(true);
 
@@ -664,13 +674,15 @@
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE);
+        int mainUser = mUms.getMainUserId();
+        assumeTrue(mUms.canAddPrivateProfile(mainUser));
         UserManagerService mSpiedUms = spy(mUms);
         mockAutoLockForPrivateSpace(Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY);
         when(mPowerManager.isInteractive()).thenReturn(false);
 
         UserInfo privateProfileUser =
                 mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
-                        USER_TYPE_PROFILE_PRIVATE, 0, 0, null);
+                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);
         Mockito.doNothing().when(mSpiedUms).scheduleMessageToAutoLockPrivateSpace(
                 eq(privateProfileUser.getUserHandle().getIdentifier()), any(),
                 anyLong());
@@ -702,8 +714,10 @@
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE);
+        int mainUser = mUms.getMainUserId();
+        assumeTrue(mUms.canAddPrivateProfile(mainUser));
         mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
-                        USER_TYPE_PROFILE_PRIVATE, 0, 0, null);
+                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);
 
         // Set the preference to auto lock on device lock
         mUms.setOrUpdateAutoLockPreferenceForPrivateProfile(
@@ -754,6 +768,7 @@
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_HIDING_PROFILES);
+        assumeTrue(mUms.canAddPrivateProfile(0));
         UserInfo privateProfileUser =
                 mUms.createProfileForUserEvenWhenDisallowedWithThrow("TestPrivateProfile",
                         USER_TYPE_PROFILE_PRIVATE, 0, 0, null);
@@ -763,23 +778,23 @@
     }
 
     @Test
+    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})
     public void testCreatePrivateProfileOnHeadlessSystemUser_shouldAllowCreation() {
-        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
-        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);
         UserManagerService mSpiedUms = spy(mUms);
+        assumeTrue(mUms.isHeadlessSystemUserMode());
         int mainUser = mSpiedUms.getMainUserId();
-        doReturn(true).when(mSpiedUms).isHeadlessSystemUserMode();
-        assertThat(mSpiedUms.canAddPrivateProfile(mainUser)).isTrue();
+        // Check whether private space creation is blocked on the device
+        assumeTrue(mSpiedUms.canAddPrivateProfile(mainUser));
         assertThat(mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(
                 PRIVATE_PROFILE_NAME, USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null)).isNotNull();
     }
 
     @Test
+    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})
     public void testCreatePrivateProfileOnSecondaryUser_shouldNotAllowCreation() {
-        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
-        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);
+        assumeTrue(mUms.canAddMoreUsersOfType(USER_TYPE_FULL_SECONDARY));
         UserInfo user = mUms.createUserWithThrow(generateLongString(), USER_TYPE_FULL_SECONDARY, 0);
         assertThat(mUms.canAddPrivateProfile(user.id)).isFalse();
         assertThrows(ServiceSpecificException.class,
@@ -788,52 +803,48 @@
     }
 
     @Test
+    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})
     public void testCreatePrivateProfileOnAutoDevices_shouldNotAllowCreation() {
-        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
-        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);
         doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_AUTOMOTIVE), anyInt());
         int mainUser = mUms.getMainUserId();
-        assertThat(mUms.canAddPrivateProfile(0)).isFalse();
+        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();
         assertThrows(ServiceSpecificException.class,
                 () -> mUms.createProfileForUserWithThrow(PRIVATE_PROFILE_NAME,
                         USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null));
     }
 
     @Test
+    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})
     public void testCreatePrivateProfileOnTV_shouldNotAllowCreation() {
-        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
-        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);
         doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_LEANBACK), anyInt());
         int mainUser = mUms.getMainUserId();
-        assertThat(mUms.canAddPrivateProfile(0)).isFalse();
+        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();
         assertThrows(ServiceSpecificException.class,
                 () -> mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
                         USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null));
     }
 
     @Test
+    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})
     public void testCreatePrivateProfileOnEmbedded_shouldNotAllowCreation() {
-        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
-        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);
         doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_EMBEDDED), anyInt());
         int mainUser = mUms.getMainUserId();
-        assertThat(mUms.canAddPrivateProfile(0)).isFalse();
+        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();
         assertThrows(ServiceSpecificException.class,
                 () -> mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
                         USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null));
     }
 
     @Test
+    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})
     public void testCreatePrivateProfileOnWatch_shouldNotAllowCreation() {
-        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
-        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);
         doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_WATCH), anyInt());
         int mainUser = mUms.getMainUserId();
-        assertThat(mUms.canAddPrivateProfile(0)).isFalse();
+        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();
         assertThrows(ServiceSpecificException.class,
                 () -> mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,
                         USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null));
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index e189098..ab36ba2 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.nullable;
 import static org.mockito.Mockito.times;
@@ -45,6 +46,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -57,6 +59,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
@@ -155,6 +158,8 @@
         mPackageInfo.applicationInfo = new ApplicationInfo();
         mPackageInfo.applicationInfo.privateFlags = ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo);
+        when(mMockPackageManager.getPackageInfoAsUser(
+                        anyString(), anyInt(), anyInt())).thenReturn(mPackageInfo);
         when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager);
         when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
         when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn(
@@ -3586,6 +3591,19 @@
         }
 
         @Override
+        public Resources getResources() {
+            Resources mockResources = mock(Resources.class);
+            // config_canRemoveFirstAccount = true
+            when(mockResources.getBoolean(anyInt())).thenReturn(true);
+            return mockResources;
+        }
+
+        @Override
+        public ContentResolver getContentResolver() {
+            return mock(ContentResolver.class);
+        }
+
+        @Override
         public void sendBroadcastAsUser(Intent intent, UserHandle user) {
             sendBroadcastAsUser(intent, user, null, null);
         }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
index 9f3f297..e4c56a7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
@@ -176,6 +176,21 @@
     }
 
     @Test
+    @RequiresFlagsEnabled({Flags.FLAG_DE_HIDL, Flags.FLAG_FACE_VHAL_FEATURE})
+    public void registerAuthenticatorsLegacy_virtualFaceOnly() throws Exception {
+        initService();
+        Settings.Secure.putInt(mSettingsRule.mockContentResolver(mContext),
+                Settings.Secure.BIOMETRIC_FACE_VIRTUAL_ENABLED, 1);
+
+        mFaceService.mServiceWrapper.registerAuthenticatorsLegacy(mFaceSensorConfigurations);
+        waitForRegistration();
+
+        verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL),
+                eq(BiometricAuthenticator.TYPE_FACE),
+                eq(Utils.propertyStrengthToAuthenticatorStrength(STRENGTH_STRONG)), any());
+    }
+
+    @Test
     @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
     public void registerAuthenticatorsLegacy_virtualAlwaysWhenNoOther() throws Exception {
         mFaceSensorConfigurations = new FaceSensorConfigurations(false);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
index 20961a9..9a8cd48 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
@@ -223,6 +223,18 @@
     }
 
     @Test
+    public void registerAuthenticators_virtualFingerprintOnly() throws Exception {
+        initServiceWith(NAME_DEFAULT, NAME_VIRTUAL);
+        Settings.Secure.putInt(mSettingsRule.mockContentResolver(mContext),
+                Settings.Secure.BIOMETRIC_FINGERPRINT_VIRTUAL_ENABLED, 1);
+
+        mService.mServiceWrapper.registerAuthenticators(HIDL_AUTHENTICATORS);
+        waitForRegistration();
+
+        verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any());
+    }
+
+    @Test
     @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
     public void registerAuthenticatorsLegacy_virtualOnly() throws Exception {
         initServiceWith(NAME_DEFAULT, NAME_VIRTUAL);
diff --git a/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
index 6c5a569..af6f6f2 100644
--- a/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
+++ b/services/tests/servicestests/src/com/android/server/grammaticalinflection/GrammaticalInflectionBackupTest.java
@@ -18,6 +18,7 @@
 
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertEquals;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -46,6 +47,7 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.List;
 
@@ -67,7 +69,7 @@
     @Before
     public void setUp() throws Exception {
         mBackupHelper = new GrammaticalInflectionBackupHelper(
-                mGrammaticalInflectionService, mMockPackageManager);
+                null, mGrammaticalInflectionService, mMockPackageManager);
     }
 
     @Test
@@ -106,6 +108,28 @@
                 eq(Configuration.GRAMMATICAL_GENDER_NEUTRAL));
     }
 
+    @Test
+    public void testSystemBackupPayload_returnsGender()
+            throws IOException, ClassNotFoundException {
+        doReturn(Configuration.GRAMMATICAL_GENDER_MASCULINE).when(mGrammaticalInflectionService)
+                .getSystemGrammaticalGender(any(), eq(DEFAULT_USER_ID));
+
+        int gender = convertByteArrayToInt(mBackupHelper.getSystemBackupPayload(DEFAULT_USER_ID));
+
+        assertEquals(gender, Configuration.GRAMMATICAL_GENDER_MASCULINE);
+    }
+
+    @Test
+    public void testApplySystemPayload_setSystemWideGrammaticalGender()
+            throws IOException {
+        mBackupHelper.applyRestoredSystemPayload(
+                intToByteArray(Configuration.GRAMMATICAL_GENDER_NEUTRAL), DEFAULT_USER_ID);
+
+        verify(mGrammaticalInflectionService).setSystemWideGrammaticalGender(
+                eq(Configuration.GRAMMATICAL_GENDER_NEUTRAL),
+                eq(DEFAULT_USER_ID));
+    }
+
     private void mockAppInstalled() {
         ApplicationInfo dummyApp = new ApplicationInfo();
         dummyApp.packageName = DEFAULT_PACKAGE_NAME;
@@ -141,4 +165,15 @@
         }
         return data;
     }
+
+    private byte[] intToByteArray(final int gender) {
+        ByteBuffer bb = ByteBuffer.allocate(4);
+        bb.putInt(gender);
+        return bb.array();
+    }
+
+    private int convertByteArrayToInt(byte[] intBytes) {
+        ByteBuffer byteBuffer = ByteBuffer.wrap(intBytes);
+        return byteBuffer.getInt();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 4405a20..b91ef7c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -1256,6 +1256,30 @@
 
     @MediumTest
     @Test
+    public void testDefaultUserRestrictionsForPrivateProfile() {
+        assumeTrue(mUserManager.canAddPrivateProfile());
+        final int currentUserId = ActivityManager.getCurrentUser();
+        UserInfo privateProfileInfo = null;
+        try {
+            privateProfileInfo = createProfileForUser("Private",
+                    UserManager.USER_TYPE_PROFILE_PRIVATE, currentUserId);
+            assertThat(privateProfileInfo).isNotNull();
+        } catch (Exception e) {
+            fail("Creation of private profile failed due to " + e.getMessage());
+        }
+        assertDefaultPrivateProfileRestrictions(privateProfileInfo.getUserHandle());
+    }
+
+    private void assertDefaultPrivateProfileRestrictions(UserHandle userHandle) {
+        Bundle defaultPrivateProfileRestrictions =
+                UserTypeFactory.getDefaultPrivateProfileRestrictions();
+        for (String restriction : defaultPrivateProfileRestrictions.keySet()) {
+            assertThat(mUserManager.hasUserRestrictionForUser(restriction, userHandle)).isTrue();
+        }
+    }
+
+    @MediumTest
+    @Test
     public void testAddRestrictedProfile() throws Exception {
         if (isAutomotive() || UserManager.isHeadlessSystemUserMode()) return;
         assertWithMessage("There should be no associated restricted profiles before the test")
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ae4faa8..9729c68 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -180,7 +180,8 @@
                 LocalServices.getService(ActivityManagerInternal.class));
         mAtmInternal = Objects.requireNonNull(
                 LocalServices.getService(ActivityTaskManagerInternal.class));
-        mWmInternal = LocalServices.getService(WindowManagerInternal.class);
+        mWmInternal = Objects.requireNonNull(
+                LocalServices.getService(WindowManagerInternal.class));
         mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
         LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService(
                 LegacyPermissionManagerInternal.class);
@@ -2737,12 +2738,8 @@
                     isManagedProfileVisible = true;
                 }
             }
-            final ScreenCapture.ScreenshotHardwareBuffer shb;
-            if (mWmInternal != null) {
-                shb = mWmInternal.takeAssistScreenshot();
-            } else {
-                shb = null;
-            }
+            final ScreenCapture.ScreenshotHardwareBuffer shb =
+                    mWmInternal.takeAssistScreenshot();
             final Bitmap bm = shb != null ? shb.asBitmap() : null;
             // Now that everything is fetched, putting it in the launchIntent.
             if (bm != null) {
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index ec60c67..0ddc38a 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -35,8 +35,6 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.flags.FeatureFlags;
-import com.android.internal.telephony.flags.FeatureFlagsImpl;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -48,8 +46,7 @@
     private static final String LOG_TAG = "TelephonyPermissions";
 
     private static final boolean DBG = false;
-    /** Feature flags */
-    private static final FeatureFlags sFeatureFlag = new FeatureFlagsImpl();
+
     /**
      * Whether to disable the new device identifier access restrictions.
      */
@@ -886,12 +883,6 @@
      */
     public static boolean checkSubscriptionAssociatedWithUser(@NonNull Context context, int subId,
             @NonNull UserHandle callerUserHandle) {
-        if (!sFeatureFlag.rejectBadSubIdInteraction()
-                && !SubscriptionManager.isValidSubscriptionId(subId)) {
-            // Return true for invalid sub Id.
-            return true;
-        }
-
         SubscriptionManager subManager = (SubscriptionManager) context.getSystemService(
                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
         final long token = Binder.clearCallingIdentity();
@@ -906,7 +897,7 @@
         } catch (IllegalArgumentException e) {
             // Found no record of this sub Id.
             Log.e(LOG_TAG, "Subscription[Subscription ID:" + subId + "] has no records on device");
-            return !sFeatureFlag.rejectBadSubIdInteraction();
+            return false;
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/tests/CompanionDeviceMultiDeviceTests/client/Android.bp b/tests/CompanionDeviceMultiDeviceTests/client/Android.bp
index 1e68c9d..9994826 100644
--- a/tests/CompanionDeviceMultiDeviceTests/client/Android.bp
+++ b/tests/CompanionDeviceMultiDeviceTests/client/Android.bp
@@ -19,10 +19,11 @@
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["frameworks_base_license"],
+    default_team: "trendy_team_framework_cdm",
 }
 
 android_test {
-    name: "cdm_snippet",
+    name: "cdm_snippet_legacy",
     srcs: ["src/**/*.kt"],
     manifest: "AndroidManifest.xml",
 
diff --git a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
index 03335c7..37cb850 100644
--- a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
+++ b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
@@ -19,6 +19,7 @@
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["frameworks_base_license"],
+    default_team: "trendy_team_framework_cdm",
 }
 
 python_test_host {
@@ -36,7 +37,7 @@
         tags: ["mobly"],
     },
     data: [
-        ":cdm_snippet",
+        ":cdm_snippet_legacy",
     ],
     version: {
         py2: {
diff --git a/tests/CompanionDeviceMultiDeviceTests/host/AndroidTest.xml b/tests/CompanionDeviceMultiDeviceTests/host/AndroidTest.xml
index 9d1813f..7c7ef63 100644
--- a/tests/CompanionDeviceMultiDeviceTests/host/AndroidTest.xml
+++ b/tests/CompanionDeviceMultiDeviceTests/host/AndroidTest.xml
@@ -24,12 +24,12 @@
 
     <device name="device1">
         <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-            <option name="test-file-name" value="cdm_snippet.apk" />
+            <option name="test-file-name" value="cdm_snippet_legacy.apk" />
         </target_preparer>
     </device>
     <device name="device2">
         <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-            <option name="test-file-name" value="cdm_snippet.apk" />
+            <option name="test-file-name" value="cdm_snippet_legacy.apk" />
         </target_preparer>
     </device>
 
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 093923f..1fdf97a 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -45,13 +45,13 @@
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.DeviceConfig;
 import android.util.AtomicFile;
-import android.util.LongArrayQueue;
 import android.util.Xml;
+import android.utils.LongArrayQueue;
+import android.utils.XmlUtils;
 
 import androidx.test.InstrumentationRegistry;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
-import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.PackageWatchdog.HealthCheckState;
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
index b506d74..56845ae 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
@@ -21,10 +21,9 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -34,9 +33,7 @@
 import android.hardware.usb.flags.Flags;
 import android.os.RemoteException;
 import android.os.UserManager;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -64,7 +61,7 @@
     @Mock
     private UsbSettingsManager mUsbSettingsManager;
     @Mock
-    private IUsbOperationInternal mIUsbOperationInternal;
+    private IUsbOperationInternal mCallback;
 
     private static final String TEST_PORT_ID = "123";
 
@@ -77,98 +74,105 @@
     private UsbService mUsbService;
 
     @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Before
     public void setUp() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_USB_DATA_SIGNAL_STAKING);
         MockitoAnnotations.initMocks(this);
-        mUsbService = new UsbService(mContext, mUsbPortManager, mUsbAlsaManager, mUserManager,
-                mUsbSettingsManager);
+
+        when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID), anyBoolean(), eq(TEST_TRANSACTION_ID),
+                eq(mCallback), any())).thenReturn(true);
+
+        mUsbService = new UsbService(mContext, mUsbPortManager, mUsbAlsaManager,
+                mUserManager, mUsbSettingsManager);
+    }
+
+    private void assertToggleUsbSuccessfully(int uid, boolean enable) {
+        assertTrue(mUsbService.enableUsbDataInternal(TEST_PORT_ID, enable,
+                TEST_TRANSACTION_ID, mCallback, uid));
+
+        verify(mUsbPortManager).enableUsbData(TEST_PORT_ID,
+                enable, TEST_TRANSACTION_ID, mCallback, null);
+        verifyZeroInteractions(mCallback);
+
+        clearInvocations(mUsbPortManager);
+        clearInvocations(mCallback);
+    }
+
+    private void assertToggleUsbFailed(int uid, boolean enable) throws Exception {
+        assertFalse(mUsbService.enableUsbDataInternal(TEST_PORT_ID, enable,
+                TEST_TRANSACTION_ID, mCallback, uid));
+
+        verifyZeroInteractions(mUsbPortManager);
+        verify(mCallback).onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+
+        clearInvocations(mUsbPortManager);
+        clearInvocations(mCallback);
     }
 
     /**
      * Verify enableUsbData successfully disables USB port without error
      */
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_USB_DATA_SIGNAL_STAKING)
-    public void usbPort_SuccessfullyDisabled() {
-        boolean enableState = false;
-        when(mUsbPortManager.enableUsbData(TEST_PORT_ID, enableState, TEST_TRANSACTION_ID,
-                mIUsbOperationInternal, null)).thenReturn(true);
-
-        assertTrue(mUsbService.enableUsbDataInternal(TEST_PORT_ID, enableState,
-                TEST_TRANSACTION_ID, mIUsbOperationInternal, TEST_FIRST_CALLER_ID));
-
-        verify(mUsbPortManager, times(1)).enableUsbData(TEST_PORT_ID,
-                enableState, TEST_TRANSACTION_ID, mIUsbOperationInternal, null);
-        verifyZeroInteractions(mIUsbOperationInternal);
+    public void disableUsb_successfullyDisable() {
+        assertToggleUsbSuccessfully(TEST_FIRST_CALLER_ID, false);
     }
 
     /**
      * Verify enableUsbData successfully enables USB port without error given no other stakers
      */
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_USB_DATA_SIGNAL_STAKING)
-    public void usbPortWhenNoOtherStakers_SuccessfullyEnabledUsb() {
-        boolean enableState = true;
-        when(mUsbPortManager.enableUsbData(TEST_PORT_ID, enableState, TEST_TRANSACTION_ID,
-                mIUsbOperationInternal, null))
-                .thenReturn(true);
-
-        assertTrue(mUsbService.enableUsbDataInternal(TEST_PORT_ID, enableState,
-                TEST_TRANSACTION_ID, mIUsbOperationInternal, TEST_FIRST_CALLER_ID));
-        verifyZeroInteractions(mIUsbOperationInternal);
+    public void enableUsbWhenNoOtherStakers_successfullyEnable() {
+        assertToggleUsbSuccessfully(TEST_FIRST_CALLER_ID, true);
     }
 
     /**
      * Verify enableUsbData does not enable USB port if other stakers are present
      */
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_USB_DATA_SIGNAL_STAKING)
-    public void usbPortWithOtherStakers_DoesNotToEnableUsb() throws RemoteException {
-        mUsbService.enableUsbDataInternal(TEST_PORT_ID, false, TEST_TRANSACTION_ID,
-                mIUsbOperationInternal, TEST_FIRST_CALLER_ID);
-        clearInvocations(mUsbPortManager);
+    public void enableUsbPortWithOtherStakers_failsToEnable() throws Exception {
+        assertToggleUsbSuccessfully(TEST_FIRST_CALLER_ID, false);
 
-        assertFalse(mUsbService.enableUsbDataInternal(TEST_PORT_ID, true,
-                TEST_TRANSACTION_ID, mIUsbOperationInternal, TEST_SECOND_CALLER_ID));
+        assertToggleUsbFailed(TEST_SECOND_CALLER_ID, true);
+    }
 
-        verifyZeroInteractions(mUsbPortManager);
-        verify(mIUsbOperationInternal).onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+    /**
+     * Verify enableUsbData successfully enables USB port when the last staker is removed
+     */
+    @Test
+    public void enableUsbByTheOnlyStaker_successfullyEnable() {
+        assertToggleUsbSuccessfully(TEST_FIRST_CALLER_ID, false);
+
+        assertToggleUsbSuccessfully(TEST_FIRST_CALLER_ID, true);
     }
 
     /**
      * Verify enableUsbDataWhileDockedInternal does not enable USB port if other stakers are present
      */
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_USB_DATA_SIGNAL_STAKING)
-    public void enableUsbWhileDockedWhenThereAreOtherStakers_DoesNotEnableUsb()
+    public void enableUsbWhileDockedWhenThereAreOtherStakers_failsToEnable()
             throws RemoteException {
-        mUsbService.enableUsbDataInternal(TEST_PORT_ID, false, TEST_TRANSACTION_ID,
-                mIUsbOperationInternal, TEST_FIRST_CALLER_ID);
+        assertToggleUsbSuccessfully(TEST_FIRST_CALLER_ID, false);
 
-        mUsbService.enableUsbDataWhileDockedInternal(TEST_PORT_ID, 0,
-                mIUsbOperationInternal, TEST_SECOND_CALLER_ID);
+        mUsbService.enableUsbDataWhileDockedInternal(TEST_PORT_ID, TEST_TRANSACTION_ID,
+                mCallback, TEST_SECOND_CALLER_ID);
 
-        verify(mUsbPortManager, never()).enableUsbDataWhileDocked(any(),
-                anyLong(), any(), any());
-        verify(mIUsbOperationInternal).onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+        verifyZeroInteractions(mUsbPortManager);
+        verify(mCallback).onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
     }
 
     /**
-     * Verify enableUsbDataWhileDockedInternal does  enable USB port if other stakers are
+     * Verify enableUsbDataWhileDockedInternal does enable USB port if other stakers are
      * not present
      */
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_USB_DATA_SIGNAL_STAKING)
-    public void enableUsbWhileDockedWhenThereAreNoStakers_SuccessfullyEnableUsb()
-            throws RemoteException {
+    public void enableUsbWhileDockedWhenThereAreNoStakers_SuccessfullyEnable() {
         mUsbService.enableUsbDataWhileDockedInternal(TEST_PORT_ID, TEST_TRANSACTION_ID,
-                mIUsbOperationInternal, TEST_SECOND_CALLER_ID);
+                mCallback, TEST_SECOND_CALLER_ID);
 
-        verify(mUsbPortManager, times(1))
-                .enableUsbDataWhileDocked(TEST_PORT_ID, TEST_TRANSACTION_ID,
-                        mIUsbOperationInternal, null);
-        verifyZeroInteractions(mIUsbOperationInternal);
+        verify(mUsbPortManager).enableUsbDataWhileDocked(TEST_PORT_ID, TEST_TRANSACTION_ID,
+                        mCallback, null);
+        verifyZeroInteractions(mCallback);
     }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java
index c1c520e..b98161d 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java
@@ -59,7 +59,8 @@
         switch (format) {
             case HUMAN_READABLE:
                 Element appMetadataBundles =
-                        XmlUtils.getSingleElement(document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES);
+                        XmlUtils.getSingleChildElement(
+                                document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES, true);
 
                 return new AndroidSafetyLabelFactory()
                         .createFromHrElements(XmlUtils.listOf(appMetadataBundles));
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java
index 112b92c..ecfad91 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java
@@ -61,4 +61,10 @@
         }
         return XmlUtils.listOf(aslEle);
     }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java
index b69c30f..41ce6e55 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java
@@ -55,4 +55,11 @@
         return new AndroidSafetyLabel(
                 version, systemAppSafetyLabel, safetyLabels, transparencyInfo);
     }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public AndroidSafetyLabel createFromOdElements(List<Element> elements)
+            throws MalformedXmlException {
+        return null;
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
index 3f1ddeb..21f328d 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
@@ -142,4 +142,10 @@
         }
         return XmlUtils.listOf(appInfoEle);
     }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
index 59a437d..6fcf637 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
@@ -72,4 +72,10 @@
                 email,
                 website);
     }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public AppInfo createFromOdElements(List<Element> elements) throws MalformedXmlException {
+        return null;
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java
index 48747cc..0a70e7d0 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java
@@ -23,6 +23,9 @@
 
 public interface AslMarshallable {
 
-    /** Creates the on-device DOM element from the AslMarshallable Java Object. */
+    /** Creates the on-device DOM elements from the AslMarshallable Java Object. */
     List<Element> toOdDomElements(Document doc);
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    List<Element> toHrDomElements(Document doc);
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java
index a49b3e7..3958290 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java
@@ -24,6 +24,9 @@
 
 public interface AslMarshallableFactory<T extends AslMarshallable> {
 
-    /** Creates an {@link AslMarshallableFactory} from human-readable DOM element */
+    /** Creates an {@link AslMarshallableFactory} from human-readable DOM elements */
     T createFromHrElements(List<Element> elements) throws MalformedXmlException;
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    T createFromOdElements(List<Element> elements) throws MalformedXmlException;
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java
index 4d67162..eb97554 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java
@@ -59,4 +59,10 @@
         }
         return XmlUtils.listOf(dataCategoryEle);
     }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java
index 37d99e7..90424fe 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java
@@ -50,4 +50,31 @@
 
         return new DataCategory(categoryName, dataTypeMap);
     }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public DataCategory createFromOdElements(List<Element> elements) throws MalformedXmlException {
+        Element dataCategoryEle = XmlUtils.getSingleElement(elements);
+        Map<String, DataType> dataTypeMap = new LinkedHashMap<String, DataType>();
+        String categoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME);
+        var odDataTypes = XmlUtils.asElementList(dataCategoryEle.getChildNodes());
+        for (Element odDataTypeEle : odDataTypes) {
+            String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME);
+            if (!DataTypeConstants.getValidDataTypes().containsKey(categoryName)) {
+                throw new MalformedXmlException(
+                        String.format("Unrecognized data category %s", categoryName));
+            }
+            if (!DataTypeConstants.getValidDataTypes().get(categoryName).contains(dataTypeName)) {
+                throw new MalformedXmlException(
+                        String.format(
+                                "Unrecognized data type name %s for category %s",
+                                dataTypeName, categoryName));
+            }
+            dataTypeMap.put(
+                    dataTypeName,
+                    new DataTypeFactory().createFromOdElements(XmlUtils.listOf(odDataTypeEle)));
+        }
+
+        return new DataCategory(categoryName, dataTypeMap);
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java
index 7516faf..4a0d759 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java
@@ -79,6 +79,16 @@
         return XmlUtils.listOf(dataLabelsEle);
     }
 
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        Element dataLabelsEle = doc.createElement(XmlUtils.HR_TAG_DATA_LABELS);
+        maybeAppendHrDataUsages(doc, dataLabelsEle, mDataAccessed, XmlUtils.HR_TAG_DATA_ACCESSED);
+        maybeAppendHrDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED);
+        maybeAppendHrDataUsages(doc, dataLabelsEle, mDataShared, XmlUtils.HR_TAG_DATA_SHARED);
+        return XmlUtils.listOf(dataLabelsEle);
+    }
+
     private void maybeAppendDataUsages(
             Document doc,
             Element dataLabelsEle,
@@ -100,4 +110,42 @@
         }
         dataLabelsEle.appendChild(dataUsageEle);
     }
+
+    private void maybeAppendHrDataUsages(
+            Document doc,
+            Element dataLabelsEle,
+            Map<String, DataCategory> dataCategoriesMap,
+            String dataUsageTypeName) {
+        if (dataCategoriesMap.isEmpty()) {
+            return;
+        }
+        for (String dataCategoryName : dataCategoriesMap.keySet()) {
+            DataCategory dataCategory = dataCategoriesMap.get(dataCategoryName);
+            for (String dataTypeName : dataCategory.getDataTypes().keySet()) {
+                DataType dataType = dataCategory.getDataTypes().get(dataTypeName);
+                // XmlUtils.appendChildren(dataLabelsEle, dataType.toHrDomElements(doc));
+                Element hrDataTypeEle = doc.createElement(dataUsageTypeName);
+                hrDataTypeEle.setAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY, dataCategoryName);
+                hrDataTypeEle.setAttribute(XmlUtils.HR_ATTR_DATA_TYPE, dataTypeName);
+                XmlUtils.maybeSetHrBoolAttr(
+                        hrDataTypeEle,
+                        XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL,
+                        dataType.getIsCollectionOptional());
+                XmlUtils.maybeSetHrBoolAttr(
+                        hrDataTypeEle,
+                        XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL,
+                        dataType.getIsSharingOptional());
+                XmlUtils.maybeSetHrBoolAttr(
+                        hrDataTypeEle, XmlUtils.HR_ATTR_EPHEMERAL, dataType.getEphemeral());
+                hrDataTypeEle.setAttribute(
+                        XmlUtils.HR_ATTR_PURPOSES,
+                        String.join(
+                                "|",
+                                dataType.getPurposes().stream()
+                                        .map(DataType.Purpose::toString)
+                                        .toList()));
+                dataLabelsEle.appendChild(hrDataTypeEle);
+            }
+        }
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java
index dc77fd0..5473e01 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java
@@ -22,7 +22,6 @@
 import com.android.asllib.util.XmlUtils;
 
 import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
 
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -46,60 +45,57 @@
                 getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_COLLECTED);
         Map<String, DataCategory> dataShared =
                 getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_SHARED);
+        DataLabels dataLabels = new DataLabels(dataAccessed, dataCollected, dataShared);
+        validateIsXOptional(dataLabels);
+        return dataLabels;
+    }
 
-        // 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()));
-                }
-            }
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public DataLabels createFromOdElements(List<Element> elements) throws MalformedXmlException {
+        Element dataLabelsEle = XmlUtils.getSingleElement(elements);
+        if (dataLabelsEle == null) {
+            AslgenUtil.logI("Found no DataLabels in od format.");
+            return null;
         }
-        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()));
-                }
-            }
-        }
+        Map<String, DataCategory> dataAccessed =
+                getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_ACCESSED);
+        Map<String, DataCategory> dataCollected =
+                getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_COLLECTED);
+        Map<String, DataCategory> dataShared =
+                getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_SHARED);
+        DataLabels dataLabels = new DataLabels(dataAccessed, dataCollected, dataShared);
+        validateIsXOptional(dataLabels);
+        return dataLabels;
+    }
 
-        return new DataLabels(dataAccessed, dataCollected, dataShared);
+    private static Map<String, DataCategory> getOdDataCategoriesWithTag(
+            Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException {
+        Map<String, DataCategory> dataCategoryMap = new LinkedHashMap<String, DataCategory>();
+        Element dataUsageEle =
+                XmlUtils.getOdPbundleWithName(dataLabelsEle, dataCategoryUsageTypeTag, false);
+        if (dataUsageEle == null) {
+            return dataCategoryMap;
+        }
+        List<Element> dataCategoryEles = XmlUtils.asElementList(dataUsageEle.getChildNodes());
+        for (Element dataCategoryEle : dataCategoryEles) {
+            String dataCategoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME);
+            DataCategory dataCategory =
+                    new DataCategoryFactory().createFromOdElements(List.of(dataCategoryEle));
+            dataCategoryMap.put(dataCategoryName, dataCategory);
+        }
+        return dataCategoryMap;
     }
 
     private static Map<String, DataCategory> getDataCategoriesWithTag(
             Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException {
-        NodeList dataUsedNodeList = dataLabelsEle.getElementsByTagName(dataCategoryUsageTypeTag);
+        List<Element> dataUsedElements =
+                XmlUtils.getChildrenByTagName(dataLabelsEle, dataCategoryUsageTypeTag);
         Map<String, DataCategory> dataCategoryMap = new LinkedHashMap<String, DataCategory>();
 
         Set<String> dataCategoryNames = new HashSet<String>();
-        for (int i = 0; i < dataUsedNodeList.getLength(); i++) {
-            Element dataUsedEle = (Element) dataUsedNodeList.item(i);
+        for (int i = 0; i < dataUsedElements.size(); i++) {
+            Element dataUsedEle = dataUsedElements.get(i);
             String dataCategoryName = dataUsedEle.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY);
             if (!DataCategoryConstants.getValidDataCategories().contains(dataCategoryName)) {
                 throw new MalformedXmlException(
@@ -109,7 +105,7 @@
         }
         for (String dataCategoryName : dataCategoryNames) {
             var dataCategoryElements =
-                    XmlUtils.asElementList(dataUsedNodeList).stream()
+                    dataUsedElements.stream()
                             .filter(
                                     ele ->
                                             ele.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY)
@@ -121,4 +117,48 @@
         }
         return dataCategoryMap;
     }
+
+    private void validateIsXOptional(DataLabels dataLabels) throws MalformedXmlException {
+        // Validate booleans such as isCollectionOptional, isSharingOptional.
+        for (DataCategory dataCategory : dataLabels.getDataAccessed().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 : dataLabels.getDataCollected().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 : dataLabels.getDataShared().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()));
+                }
+            }
+        }
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java
index 3471362..02b7189 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java
@@ -160,6 +160,12 @@
         return XmlUtils.listOf(dataTypeEle);
     }
 
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
+
     private static void maybeAddBoolToOdElement(
             Document doc, Element parentEle, Boolean b, String odName) {
         if (b == null) {
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java
index ed434cd..488c259 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java
@@ -51,4 +51,31 @@
         return new DataType(
                 dataTypeName, purposes, isCollectionOptional, isSharingOptional, ephemeral);
     }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public DataType createFromOdElements(List<Element> elements) throws MalformedXmlException {
+        Element odDataTypeEle = XmlUtils.getSingleElement(elements);
+        String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME);
+        List<Integer> purposeInts =
+                XmlUtils.getOdIntArray(odDataTypeEle, XmlUtils.OD_NAME_PURPOSES, true);
+        List<DataType.Purpose> purposes =
+                purposeInts.stream().map(DataType.Purpose::forValue).collect(Collectors.toList());
+        if (purposes.isEmpty()) {
+            throw new MalformedXmlException(String.format("Found no purpose in: %s", dataTypeName));
+        }
+        if (new HashSet<>(purposes).size() != purposes.size()) {
+            throw new MalformedXmlException(
+                    String.format("Found non-unique purposes in: %s", dataTypeName));
+        }
+        Boolean isCollectionOptional =
+                XmlUtils.getOdBoolEle(
+                        odDataTypeEle, XmlUtils.OD_NAME_IS_COLLECTION_OPTIONAL, false);
+        Boolean isSharingOptional =
+                XmlUtils.getOdBoolEle(odDataTypeEle, XmlUtils.OD_NAME_IS_SHARING_OPTIONAL, false);
+        Boolean ephemeral = XmlUtils.getOdBoolEle(odDataTypeEle, XmlUtils.OD_NAME_EPHEMERAL, false);
+
+        return new DataType(
+                dataTypeName, purposes, isCollectionOptional, isSharingOptional, ephemeral);
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java
index 382a1f0..efdc8d0 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java
@@ -139,4 +139,10 @@
 
         return XmlUtils.listOf(developerInfoEle);
     }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java
index b5310ba..c3e7ac3 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java
@@ -57,4 +57,10 @@
                 website,
                 appDeveloperRegistryId);
     }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public DeveloperInfo createFromOdElements(List<Element> elements) throws MalformedXmlException {
+        return null;
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
index 22c3fd8..576820d 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
@@ -28,10 +28,18 @@
 
     private final Long mVersion;
     private final DataLabels mDataLabels;
+    private final SecurityLabels mSecurityLabels;
+    private final ThirdPartyVerification mThirdPartyVerification;
 
-    public SafetyLabels(Long version, DataLabels dataLabels) {
+    public SafetyLabels(
+            Long version,
+            DataLabels dataLabels,
+            SecurityLabels securityLabels,
+            ThirdPartyVerification thirdPartyVerification) {
         this.mVersion = version;
         this.mDataLabels = dataLabels;
+        this.mSecurityLabels = securityLabels;
+        this.mThirdPartyVerification = thirdPartyVerification;
     }
 
     /** Returns the data label for the safety label */
@@ -54,6 +62,18 @@
         if (mDataLabels != null) {
             XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc));
         }
+        if (mSecurityLabels != null) {
+            XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toOdDomElements(doc));
+        }
+        if (mThirdPartyVerification != null) {
+            XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toOdDomElements(doc));
+        }
         return XmlUtils.listOf(safetyLabelsEle);
     }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
index 6bf8ef3..7e1838f 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
@@ -44,6 +44,28 @@
                                                 safetyLabelsEle,
                                                 XmlUtils.HR_TAG_DATA_LABELS,
                                                 false)));
-        return new SafetyLabels(version, dataLabels);
+        SecurityLabels securityLabels =
+                new SecurityLabelsFactory()
+                        .createFromHrElements(
+                                XmlUtils.listOf(
+                                        XmlUtils.getSingleChildElement(
+                                                safetyLabelsEle,
+                                                XmlUtils.HR_TAG_SECURITY_LABELS,
+                                                false)));
+        ThirdPartyVerification thirdPartyVerification =
+                new ThirdPartyVerificationFactory()
+                        .createFromHrElements(
+                                XmlUtils.listOf(
+                                        XmlUtils.getSingleChildElement(
+                                                safetyLabelsEle,
+                                                XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION,
+                                                false)));
+        return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification);
+    }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public SafetyLabels createFromOdElements(List<Element> elements) throws MalformedXmlException {
+        return null;
     }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java
new file mode 100644
index 0000000..437343b
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java
@@ -0,0 +1,59 @@
+/*
+ * 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.marshallable;
+
+import com.android.asllib.util.XmlUtils;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+/** Security Labels representation */
+public class SecurityLabels implements AslMarshallable {
+
+    private final Boolean mIsDataDeletable;
+    private final Boolean mIsDataEncrypted;
+
+    public SecurityLabels(Boolean isDataDeletable, Boolean isDataEncrypted) {
+        this.mIsDataDeletable = isDataDeletable;
+        this.mIsDataEncrypted = isDataEncrypted;
+    }
+
+    /** Creates an on-device DOM element from the {@link SecurityLabels}. */
+    @Override
+    public List<Element> toOdDomElements(Document doc) {
+        Element ele = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SECURITY_LABELS);
+        if (mIsDataDeletable != null) {
+            ele.appendChild(
+                    XmlUtils.createOdBooleanEle(
+                            doc, XmlUtils.OD_NAME_IS_DATA_DELETABLE, mIsDataDeletable));
+        }
+        if (mIsDataEncrypted != null) {
+            ele.appendChild(
+                    XmlUtils.createOdBooleanEle(
+                            doc, XmlUtils.OD_NAME_IS_DATA_ENCRYPTED, mIsDataEncrypted));
+        }
+        return XmlUtils.listOf(ele);
+    }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java
new file mode 100644
index 0000000..9dc4712c
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java
@@ -0,0 +1,51 @@
+/*
+ * 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.marshallable;
+
+import com.android.asllib.util.AslgenUtil;
+import com.android.asllib.util.MalformedXmlException;
+import com.android.asllib.util.XmlUtils;
+
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+public class SecurityLabelsFactory implements AslMarshallableFactory<SecurityLabels> {
+
+    /** Creates a {@link SecurityLabels} from the human-readable DOM element. */
+    @Override
+    public SecurityLabels createFromHrElements(List<Element> elements)
+            throws MalformedXmlException {
+        Element ele = XmlUtils.getSingleElement(elements);
+        if (ele == null) {
+            AslgenUtil.logI("No SecurityLabels found in hr format.");
+            return null;
+        }
+        Boolean isDataDeletable =
+                XmlUtils.getBoolAttr(ele, XmlUtils.HR_ATTR_IS_DATA_DELETABLE, false);
+        Boolean isDataEncrypted =
+                XmlUtils.getBoolAttr(ele, XmlUtils.HR_ATTR_IS_DATA_ENCRYPTED, false);
+        return new SecurityLabels(isDataDeletable, isDataEncrypted);
+    }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public SecurityLabels createFromOdElements(List<Element> elements)
+            throws MalformedXmlException {
+        return null;
+    }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java
index 595d748..f0ecf93 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java
@@ -46,4 +46,10 @@
                 XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl));
         return XmlUtils.listOf(systemAppSafetyLabelEle);
     }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java
index f999559..5b7fe32 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java
@@ -39,4 +39,11 @@
         String url = XmlUtils.getStringAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_URL);
         return new SystemAppSafetyLabel(url);
     }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public SystemAppSafetyLabel createFromOdElements(List<Element> elements)
+            throws MalformedXmlException {
+        return null;
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java
new file mode 100644
index 0000000..229b002
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java
@@ -0,0 +1,49 @@
+/*
+ * 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.marshallable;
+
+import com.android.asllib.util.XmlUtils;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+/** ThirdPartyVerification representation. */
+public class ThirdPartyVerification implements AslMarshallable {
+
+    private final String mUrl;
+
+    public ThirdPartyVerification(String url) {
+        this.mUrl = url;
+    }
+
+    /** Creates an on-device DOM element from the {@link ThirdPartyVerification}. */
+    @Override
+    public List<Element> toOdDomElements(Document doc) {
+        Element ele =
+                XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION);
+        ele.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl));
+        return XmlUtils.listOf(ele);
+    }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java
new file mode 100644
index 0000000..ac4d383
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.marshallable;
+
+import com.android.asllib.util.AslgenUtil;
+import com.android.asllib.util.MalformedXmlException;
+import com.android.asllib.util.XmlUtils;
+
+import org.w3c.dom.Element;
+
+import java.util.List;
+
+public class ThirdPartyVerificationFactory
+        implements AslMarshallableFactory<ThirdPartyVerification> {
+
+    /** Creates a {@link ThirdPartyVerification} from the human-readable DOM element. */
+    @Override
+    public ThirdPartyVerification createFromHrElements(List<Element> elements)
+            throws MalformedXmlException {
+        Element ele = XmlUtils.getSingleElement(elements);
+        if (ele == null) {
+            AslgenUtil.logI("No ThirdPartyVerification found in hr format.");
+            return null;
+        }
+
+        String url = XmlUtils.getStringAttr(ele, XmlUtils.HR_ATTR_URL);
+        return new ThirdPartyVerification(url);
+    }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public ThirdPartyVerification createFromOdElements(List<Element> elements)
+            throws MalformedXmlException {
+        return null;
+    }
+}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
index ddd3557..ce7ef16 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
@@ -57,4 +57,10 @@
         }
         return XmlUtils.listOf(transparencyInfoEle);
     }
+
+    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
+    @Override
+    public List<Element> toHrDomElements(Document doc) {
+        return List.of();
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
index d9c2af4..123de01 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
@@ -49,4 +49,11 @@
 
         return new TransparencyInfo(developerInfo, appInfo);
     }
+
+    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
+    @Override
+    public TransparencyInfo createFromOdElements(List<Element> elements)
+            throws MalformedXmlException {
+        return null;
+    }
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
index 691f92f..4f21b0c 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
@@ -16,8 +16,10 @@
 
 package com.android.asllib.util;
 
+
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import java.util.ArrayList;
@@ -32,6 +34,8 @@
     public static final String HR_TAG_DEVELOPER_INFO = "developer-info";
     public static final String HR_TAG_APP_INFO = "app-info";
     public static final String HR_TAG_DATA_LABELS = "data-labels";
+    public static final String HR_TAG_SECURITY_LABELS = "security-labels";
+    public static final String HR_TAG_THIRD_PARTY_VERIFICATION = "third-party-verification";
     public static final String HR_TAG_DATA_ACCESSED = "data-accessed";
     public static final String HR_TAG_DATA_COLLECTED = "data-collected";
     public static final String HR_TAG_DATA_SHARED = "data-shared";
@@ -46,6 +50,8 @@
     public static final String HR_ATTR_DATA_TYPE = "dataType";
     public static final String HR_ATTR_IS_COLLECTION_OPTIONAL = "isCollectionOptional";
     public static final String HR_ATTR_IS_SHARING_OPTIONAL = "isSharingOptional";
+    public static final String HR_ATTR_IS_DATA_DELETABLE = "isDataDeletable";
+    public static final String HR_ATTR_IS_DATA_ENCRYPTED = "isDataEncrypted";
     public static final String HR_ATTR_EPHEMERAL = "ephemeral";
     public static final String HR_ATTR_PURPOSES = "purposes";
     public static final String HR_ATTR_VERSION = "version";
@@ -98,6 +104,8 @@
     public static final String OD_NAME_VERSION = "version";
     public static final String OD_NAME_URL = "url";
     public static final String OD_NAME_SYSTEM_APP_SAFETY_LABEL = "system_app_safety_label";
+    public static final String OD_NAME_SECURITY_LABELS = "security_labels";
+    public static final String OD_NAME_THIRD_PARTY_VERIFICATION = "third_party_verification";
     public static final String OD_NAME_DATA_LABELS = "data_labels";
     public static final String OD_NAME_DATA_ACCESSED = "data_accessed";
     public static final String OD_NAME_DATA_COLLECTED = "data_collected";
@@ -105,64 +113,44 @@
     public static final String OD_NAME_PURPOSES = "purposes";
     public static final String OD_NAME_IS_COLLECTION_OPTIONAL = "is_collection_optional";
     public static final String OD_NAME_IS_SHARING_OPTIONAL = "is_sharing_optional";
+    public static final String OD_NAME_IS_DATA_DELETABLE = "is_data_deletable";
+    public static final String OD_NAME_IS_DATA_ENCRYPTED = "is_data_encrypted";
     public static final String OD_NAME_EPHEMERAL = "ephemeral";
 
     public static final String TRUE_STR = "true";
     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)
-            throws MalformedXmlException {
-        var elements = doc.getElementsByTagName(tagName);
-        return getSingleElement(elements, tagName);
+    /** Gets the top-level children with the tag name.. */
+    public static List<Element> getChildrenByTagName(Node parentEle, String tagName) {
+        var elements = XmlUtils.asElementList(parentEle.getChildNodes());
+        return elements.stream().filter(e -> e.getTagName().equals(tagName)).toList();
     }
 
     /**
      * 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(Node parentEle, String tagName, boolean required)
             throws MalformedXmlException {
-        var elements = parentEle.getElementsByTagName(tagName);
-        return getSingleElement(elements, tagName, true);
-    }
+        String parentTagNameForErrorMsg =
+                (parentEle instanceof Element) ? ((Element) parentEle).getTagName() : "Node";
+        var elements = getChildrenByTagName(parentEle, tagName);
 
-    /**
-     * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
-     */
-    public static Element getSingleChildElement(Element parentEle, String tagName, boolean required)
-            throws MalformedXmlException {
-        var elements = parentEle.getElementsByTagName(tagName);
-        return getSingleElement(elements, tagName, required);
-    }
-
-    /** Gets the single {@link Element} from {@param elements} */
-    public static Element getSingleElement(NodeList elements, String tagName)
-            throws MalformedXmlException {
-        return getSingleElement(elements, tagName, true);
-    }
-
-    /** Gets the single {@link Element} from {@param elements} */
-    public static Element getSingleElement(NodeList elements, String tagName, boolean required)
-            throws MalformedXmlException {
-        if (elements.getLength() > 1) {
+        if (elements.size() > 1) {
             throw new MalformedXmlException(
                     String.format(
-                            "Expected 1 element \"%s\" in NodeList but got %s.",
-                            tagName, elements.getLength()));
-        } else if (elements.getLength() == 0) {
+                            "Expected 1 %s in %s but got %s.",
+                            tagName, parentTagNameForErrorMsg, elements.size()));
+        } else if (elements.isEmpty()) {
             if (required) {
                 throw new MalformedXmlException(
-                        String.format("Found no element \"%s\" in NodeList.", tagName));
+                        String.format(
+                                "Expected 1 %s in %s but got 0.",
+                                tagName, parentTagNameForErrorMsg));
             } else {
                 return null;
             }
         }
-        var elementAsNode = elements.item(0);
-        if (!(elementAsNode instanceof Element)) {
-            throw new MalformedXmlException(
-                    String.format("%s was not a valid XML element.", tagName));
-        }
-        return ((Element) elementAsNode);
+        return elements.get(0);
     }
 
     /** Gets the single {@link Element} within {@param elements}. */
@@ -221,6 +209,13 @@
         return ele;
     }
 
+    /** Sets human-readable bool attribute if non-null. */
+    public static void maybeSetHrBoolAttr(Element ele, String attrName, Boolean b) {
+        if (b != null) {
+            ele.setAttribute(attrName, String.valueOf(b));
+        }
+    }
+
     /** Create an on-device Long DOM Element with the given attribute name. */
     public static Element createOdLongEle(Document doc, String name, long l) {
         var ele = doc.createElement(XmlUtils.OD_TAG_LONG);
@@ -295,6 +290,57 @@
         return b;
     }
 
+    /** Gets a Boolean attribute. */
+    public static Boolean getOdBoolEle(Element ele, String nameName, boolean required)
+            throws MalformedXmlException {
+        List<Element> boolEles =
+                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_BOOLEAN).stream()
+                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName))
+                        .toList();
+        if (boolEles.size() > 1) {
+            throw new MalformedXmlException(
+                    String.format("Found more than one %s in %s.", nameName, ele.getTagName()));
+        }
+        if (boolEles.isEmpty()) {
+            if (required) {
+                throw new MalformedXmlException(
+                        String.format("Found no %s in %s.", nameName, ele.getTagName()));
+            }
+            return null;
+        }
+        Element boolEle = boolEles.get(0);
+
+        Boolean b = XmlUtils.fromString(boolEle.getAttribute(XmlUtils.OD_ATTR_VALUE));
+        if (b == null && required) {
+            throw new MalformedXmlException(
+                    String.format(
+                            "Boolean %s was required but missing, in %s.",
+                            nameName, ele.getTagName()));
+        }
+        return b;
+    }
+
+    /** Gets a OD Pbundle Element attribute with the specified name. */
+    public static Element getOdPbundleWithName(Element ele, String nameName, boolean required)
+            throws MalformedXmlException {
+        List<Element> eles =
+                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_PBUNDLE_AS_MAP).stream()
+                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName))
+                        .toList();
+        if (eles.size() > 1) {
+            throw new MalformedXmlException(
+                    String.format("Found more than one %s in %s.", nameName, ele.getTagName()));
+        }
+        if (eles.isEmpty()) {
+            if (required) {
+                throw new MalformedXmlException(
+                        String.format("Found no %s in %s.", nameName, ele.getTagName()));
+            }
+            return null;
+        }
+        return eles.get(0);
+    }
+
     /** Gets a required String attribute. */
     public static String getStringAttr(Element ele, String attrName) throws MalformedXmlException {
         return getStringAttr(ele, attrName, true);
@@ -317,6 +363,33 @@
         return s;
     }
 
+    /** Gets on-device style int array. */
+    public static List<Integer> getOdIntArray(Element ele, String nameName, boolean required)
+            throws MalformedXmlException {
+        List<Element> intArrayEles =
+                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_INT_ARRAY).stream()
+                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName))
+                        .toList();
+        if (intArrayEles.size() > 1) {
+            throw new MalformedXmlException(
+                    String.format("Found more than one %s in %s.", nameName, ele.getTagName()));
+        }
+        if (intArrayEles.isEmpty()) {
+            if (required) {
+                throw new MalformedXmlException(
+                        String.format("Found no %s in %s.", nameName, ele.getTagName()));
+            }
+            return List.of();
+        }
+        Element intArrayEle = intArrayEles.get(0);
+        List<Element> itemEles = XmlUtils.getChildrenByTagName(intArrayEle, XmlUtils.OD_TAG_ITEM);
+        List<Integer> ints = new ArrayList<Integer>();
+        for (Element itemEle : itemEles) {
+            ints.add(Integer.parseInt(XmlUtils.getStringAttr(itemEle, XmlUtils.OD_ATTR_VALUE)));
+        }
+        return ints;
+    }
+
     /**
      * Utility method for making a List from one element, to support easier refactoring if needed.
      * For example, List.of() doesn't support null elements.
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java
index 03e8ac6..54c80f6 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java
@@ -17,9 +17,15 @@
 package com.android.asllib;
 
 import com.android.asllib.marshallable.AndroidSafetyLabelTest;
+import com.android.asllib.marshallable.AppInfoTest;
 import com.android.asllib.marshallable.DataCategoryTest;
 import com.android.asllib.marshallable.DataLabelsTest;
 import com.android.asllib.marshallable.DeveloperInfoTest;
+import com.android.asllib.marshallable.SafetyLabelsTest;
+import com.android.asllib.marshallable.SecurityLabelsTest;
+import com.android.asllib.marshallable.SystemAppSafetyLabelTest;
+import com.android.asllib.marshallable.ThirdPartyVerificationTest;
+import com.android.asllib.marshallable.TransparencyInfoTest;
 
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -28,8 +34,14 @@
 @Suite.SuiteClasses({
     AslgenTests.class,
     AndroidSafetyLabelTest.class,
-    DeveloperInfoTest.class,
+    AppInfoTest.class,
     DataCategoryTest.class,
     DataLabelsTest.class,
+    DeveloperInfoTest.class,
+    SafetyLabelsTest.class,
+    SecurityLabelsTest.class,
+    SystemAppSafetyLabelTest.class,
+    ThirdPartyVerificationTest.class,
+    TransparencyInfoTest.class
 })
 public class AllTests {}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java
index 5f43008..e2588d7 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java
@@ -34,7 +34,8 @@
 @RunWith(JUnit4.class)
 public class AslgenTests {
     private static final String VALID_MAPPINGS_PATH = "com/android/asllib/validmappings";
-    private static final List<String> VALID_MAPPINGS_SUBDIRS = List.of("location", "contacts");
+    private static final List<String> VALID_MAPPINGS_SUBDIRS =
+            List.of("location", "contacts", "general");
     private static final String HR_XML_FILENAME = "hr.xml";
     private static final String OD_XML_FILENAME = "od.xml";
 
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java
index 2be447e..6f6f254 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java
@@ -41,6 +41,30 @@
     private static final String SHARED_INVALID_BOOL_FILE_NAME =
             "data-labels-shared-invalid-bool.xml";
 
+    private static final String ACTIONS_IN_APP_FILE_NAME = "data-category-actions-in-app.xml";
+    private static final String APP_PERFORMANCE_FILE_NAME = "data-category-app-performance.xml";
+    private static final String AUDIO_FILE_NAME = "data-category-audio.xml";
+    private static final String CALENDAR_FILE_NAME = "data-category-calendar.xml";
+    private static final String CONTACTS_FILE_NAME = "data-category-contacts.xml";
+    private static final String EMAIL_TEXT_MESSAGE_FILE_NAME =
+            "data-category-email-text-message.xml";
+    private static final String FINANCIAL_FILE_NAME = "data-category-financial.xml";
+    private static final String HEALTH_FITNESS_FILE_NAME = "data-category-health-fitness.xml";
+    private static final String IDENTIFIERS_FILE_NAME = "data-category-identifiers.xml";
+    private static final String LOCATION_FILE_NAME = "data-category-location.xml";
+    private static final String PERSONAL_FILE_NAME = "data-category-personal.xml";
+    private static final String PERSONAL_PARTIAL_FILE_NAME = "data-category-personal-partial.xml";
+    private static final String PHOTO_VIDEO_FILE_NAME = "data-category-photo-video.xml";
+    private static final String SEARCH_AND_BROWSING_FILE_NAME =
+            "data-category-search-and-browsing.xml";
+    private static final String STORAGE_FILE_NAME = "data-category-storage.xml";
+    private static final String PERSONAL_MISSING_PURPOSE_FILE_NAME =
+            "data-category-personal-missing-purpose.xml";
+    private static final String PERSONAL_EMPTY_PURPOSE_FILE_NAME =
+            "data-category-personal-empty-purpose.xml";
+    private static final String UNRECOGNIZED_FILE_NAME = "data-category-unrecognized.xml";
+    private static final String UNRECOGNIZED_TYPE_FILE_NAME = "data-category-unrecognized-type.xml";
+
     private Document mDoc = null;
 
     @Before
@@ -54,6 +78,7 @@
     public void testDataLabelsAccessedValidBool() throws Exception {
         System.out.println("starting testDataLabelsAccessedValidBool.");
         testHrToOdDataLabels(ACCESSED_VALID_BOOL_FILE_NAME);
+        testOdToHrDataLabels(ACCESSED_VALID_BOOL_FILE_NAME);
     }
 
     /** Test for data labels accessed invalid bool. */
@@ -68,6 +93,7 @@
     public void testDataLabelsCollectedValidBool() throws Exception {
         System.out.println("starting testDataLabelsCollectedValidBool.");
         testHrToOdDataLabels(COLLECTED_VALID_BOOL_FILE_NAME);
+        testOdToHrDataLabels(COLLECTED_VALID_BOOL_FILE_NAME);
     }
 
     /** Test for data labels collected invalid bool. */
@@ -75,6 +101,7 @@
     public void testDataLabelsCollectedInvalidBool() throws Exception {
         System.out.println("starting testDataLabelsCollectedInvalidBool.");
         hrToOdExpectException(COLLECTED_INVALID_BOOL_FILE_NAME);
+        odToHrExpectException(COLLECTED_INVALID_BOOL_FILE_NAME);
     }
 
     /** Test for data labels shared valid bool. */
@@ -82,6 +109,7 @@
     public void testDataLabelsSharedValidBool() throws Exception {
         System.out.println("starting testDataLabelsSharedValidBool.");
         testHrToOdDataLabels(SHARED_VALID_BOOL_FILE_NAME);
+        testOdToHrDataLabels(SHARED_VALID_BOOL_FILE_NAME);
     }
 
     /** Test for data labels shared invalid bool. */
@@ -91,12 +119,207 @@
         hrToOdExpectException(SHARED_INVALID_BOOL_FILE_NAME);
     }
 
+    /* Data categories bidirectional tests... */
+
+    /** Test for data labels actions in app. */
+    @Test
+    public void testDataLabelsActionsInApp() throws Exception {
+        System.out.println("starting testDataLabelsActionsInApp.");
+        testHrToOdDataLabels(ACTIONS_IN_APP_FILE_NAME);
+        testOdToHrDataLabels(ACTIONS_IN_APP_FILE_NAME);
+    }
+
+    /** Test for data labels app performance. */
+    @Test
+    public void testDataLabelsAppPerformance() throws Exception {
+        System.out.println("starting testDataLabelsAppPerformance.");
+        testHrToOdDataLabels(APP_PERFORMANCE_FILE_NAME);
+        testOdToHrDataLabels(APP_PERFORMANCE_FILE_NAME);
+    }
+
+    /** Test for data labels audio. */
+    @Test
+    public void testDataLabelsAudio() throws Exception {
+        System.out.println("starting testDataLabelsAudio.");
+        testHrToOdDataLabels(AUDIO_FILE_NAME);
+        testOdToHrDataLabels(AUDIO_FILE_NAME);
+    }
+
+    /** Test for data labels calendar. */
+    @Test
+    public void testDataLabelsCalendar() throws Exception {
+        System.out.println("starting testDataLabelsCalendar.");
+        testHrToOdDataLabels(CALENDAR_FILE_NAME);
+        testOdToHrDataLabels(CALENDAR_FILE_NAME);
+    }
+
+    /** Test for data labels contacts. */
+    @Test
+    public void testDataLabelsContacts() throws Exception {
+        System.out.println("starting testDataLabelsContacts.");
+        testHrToOdDataLabels(CONTACTS_FILE_NAME);
+        testOdToHrDataLabels(CONTACTS_FILE_NAME);
+    }
+
+    /** Test for data labels email text message. */
+    @Test
+    public void testDataLabelsEmailTextMessage() throws Exception {
+        System.out.println("starting testDataLabelsEmailTextMessage.");
+        testHrToOdDataLabels(EMAIL_TEXT_MESSAGE_FILE_NAME);
+        testOdToHrDataLabels(EMAIL_TEXT_MESSAGE_FILE_NAME);
+    }
+
+    /** Test for data labels financial. */
+    @Test
+    public void testDataLabelsFinancial() throws Exception {
+        System.out.println("starting testDataLabelsFinancial.");
+        testHrToOdDataLabels(FINANCIAL_FILE_NAME);
+        testOdToHrDataLabels(FINANCIAL_FILE_NAME);
+    }
+
+    /** Test for data labels health fitness. */
+    @Test
+    public void testDataLabelsHealthFitness() throws Exception {
+        System.out.println("starting testDataLabelsHealthFitness.");
+        testHrToOdDataLabels(HEALTH_FITNESS_FILE_NAME);
+        testOdToHrDataLabels(HEALTH_FITNESS_FILE_NAME);
+    }
+
+    /** Test for data labels identifiers. */
+    @Test
+    public void testDataLabelsIdentifiers() throws Exception {
+        System.out.println("starting testDataLabelsIdentifiers.");
+        testHrToOdDataLabels(IDENTIFIERS_FILE_NAME);
+        testOdToHrDataLabels(IDENTIFIERS_FILE_NAME);
+    }
+
+    /** Test for data labels location. */
+    @Test
+    public void testDataLabelsLocation() throws Exception {
+        System.out.println("starting testDataLabelsLocation.");
+        testHrToOdDataLabels(LOCATION_FILE_NAME);
+        testOdToHrDataLabels(LOCATION_FILE_NAME);
+    }
+
+    /** Test for data labels personal. */
+    @Test
+    public void testDataLabelsPersonal() throws Exception {
+        System.out.println("starting testDataLabelsPersonal.");
+        testHrToOdDataLabels(PERSONAL_FILE_NAME);
+        testOdToHrDataLabels(PERSONAL_FILE_NAME);
+    }
+
+    /** Test for data labels personal partial. */
+    @Test
+    public void testDataLabelsPersonalPartial() throws Exception {
+        System.out.println("starting testDataLabelsPersonalPartial.");
+        testHrToOdDataLabels(PERSONAL_PARTIAL_FILE_NAME);
+        testOdToHrDataLabels(PERSONAL_PARTIAL_FILE_NAME);
+    }
+
+    /** Test for data labels photo video. */
+    @Test
+    public void testDataLabelsPhotoVideo() throws Exception {
+        System.out.println("starting testDataLabelsPhotoVideo.");
+        testHrToOdDataLabels(PHOTO_VIDEO_FILE_NAME);
+        testOdToHrDataLabels(PHOTO_VIDEO_FILE_NAME);
+    }
+
+    /** Test for data labels search and browsing. */
+    @Test
+    public void testDataLabelsSearchAndBrowsing() throws Exception {
+        System.out.println("starting testDataLabelsSearchAndBrowsing.");
+        testHrToOdDataLabels(SEARCH_AND_BROWSING_FILE_NAME);
+        testOdToHrDataLabels(SEARCH_AND_BROWSING_FILE_NAME);
+    }
+
+    /** Test for data labels storage. */
+    @Test
+    public void testDataLabelsStorage() throws Exception {
+        System.out.println("starting testDataLabelsStorage.");
+        testHrToOdDataLabels(STORAGE_FILE_NAME);
+        testOdToHrDataLabels(STORAGE_FILE_NAME);
+    }
+
+    /** Test for data labels hr unrecognized data category. */
+    @Test
+    public void testDataLabelsHrUnrecognizedDataCategory() throws Exception {
+        System.out.println("starting testDataLabelsHrUnrecognizedDataCategory.");
+        hrToOdExpectException(UNRECOGNIZED_FILE_NAME);
+    }
+
+    /** Test for data labels hr unrecognized data type. */
+    @Test
+    public void testDataLabelsHrUnrecognizedDataType() throws Exception {
+        System.out.println("starting testDataLabelsHrUnrecognizedDataType.");
+        hrToOdExpectException(UNRECOGNIZED_TYPE_FILE_NAME);
+    }
+
+    /** Test for data labels hr missing purpose. */
+    @Test
+    public void testDataLabelsHrMissingPurpose() throws Exception {
+        System.out.println("starting testDataLabelsHrMissingPurpose.");
+        hrToOdExpectException(PERSONAL_MISSING_PURPOSE_FILE_NAME);
+    }
+
+    /** Test for data labels hr empty purpose. */
+    @Test
+    public void testDataLabelsHrEmptyPurpose() throws Exception {
+        System.out.println("starting testDataLabelsHrEmptyPurpose.");
+        hrToOdExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME);
+    }
+
+    /** Test for data labels od unrecognized data category. */
+    @Test
+    public void testDataLabelsOdUnrecognizedDataCategory() throws Exception {
+        System.out.println("starting testDataLabelsOdUnrecognizedDataCategory.");
+        odToHrExpectException(UNRECOGNIZED_FILE_NAME);
+    }
+
+    /** Test for data labels od unrecognized data type. */
+    @Test
+    public void testDataLabelsOdUnrecognizedDataType() throws Exception {
+        System.out.println("starting testDataLabelsOdUnrecognizedDataCategory.");
+        odToHrExpectException(UNRECOGNIZED_TYPE_FILE_NAME);
+    }
+
+    /** Test for data labels od missing purpose. */
+    @Test
+    public void testDataLabelsOdMissingPurpose() throws Exception {
+        System.out.println("starting testDataLabelsOdMissingPurpose.");
+        odToHrExpectException(PERSONAL_MISSING_PURPOSE_FILE_NAME);
+    }
+
+    /** Test for data labels od empty purpose. */
+    @Test
+    public void testDataLabelsOdEmptyPurpose() throws Exception {
+        System.out.println("starting testDataLabelsOdEmptyPurpose.");
+        odToHrExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME);
+    }
+
     private void hrToOdExpectException(String fileName) {
         TestUtils.hrToOdExpectException(new DataLabelsFactory(), DATA_LABELS_HR_PATH, fileName);
     }
 
+    private void odToHrExpectException(String fileName) {
+        TestUtils.odToHrExpectException(new DataLabelsFactory(), DATA_LABELS_OD_PATH, fileName);
+    }
+
     private void testHrToOdDataLabels(String fileName) throws Exception {
         TestUtils.testHrToOd(
-                mDoc, new DataLabelsFactory(), DATA_LABELS_HR_PATH, DATA_LABELS_OD_PATH, fileName);
+                TestUtils.document(),
+                new DataLabelsFactory(),
+                DATA_LABELS_HR_PATH,
+                DATA_LABELS_OD_PATH,
+                fileName);
+    }
+
+    private void testOdToHrDataLabels(String fileName) throws Exception {
+        TestUtils.testOdToHr(
+                TestUtils.document(),
+                new DataLabelsFactory(),
+                DATA_LABELS_OD_PATH,
+                DATA_LABELS_HR_PATH,
+                fileName);
     }
 }
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
index b62620e..c52d6c8 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
@@ -32,6 +32,9 @@
     private static final String MISSING_VERSION_FILE_NAME = "missing-version.xml";
     private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml";
     private static final String WITH_DATA_LABELS_FILE_NAME = "with-data-labels.xml";
+    private static final String WITH_SECURITY_LABELS_FILE_NAME = "with-security-labels.xml";
+    private static final String WITH_THIRD_PARTY_VERIFICATION_FILE_NAME =
+            "with-third-party-verification.xml";
 
     private Document mDoc = null;
 
@@ -62,6 +65,20 @@
         testHrToOdSafetyLabels(WITH_DATA_LABELS_FILE_NAME);
     }
 
+    /** Test for safety labels with security labels. */
+    @Test
+    public void testSafetyLabelsWithSecurityLabels() throws Exception {
+        System.out.println("starting testSafetyLabelsWithSecurityLabels.");
+        testHrToOdSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME);
+    }
+
+    /** Test for safety labels with third party verification. */
+    @Test
+    public void testSafetyLabelsWithThirdPartyVerification() throws Exception {
+        System.out.println("starting testSafetyLabelsWithThirdPartyVerification.");
+        testHrToOdSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME);
+    }
+
     private void hrToOdExpectException(String fileName) {
         TestUtils.hrToOdExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_HR_PATH, fileName);
     }
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java
new file mode 100644
index 0000000..c0d0d72
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.marshallable;
+
+
+import com.android.asllib.testutils.TestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.w3c.dom.Document;
+
+import java.nio.file.Paths;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class SecurityLabelsTest {
+    private static final String SECURITY_LABELS_HR_PATH = "com/android/asllib/securitylabels/hr";
+    private static final String SECURITY_LABELS_OD_PATH = "com/android/asllib/securitylabels/od";
+
+    public static final List<String> OPTIONAL_FIELD_NAMES =
+            List.of("isDataDeletable", "isDataEncrypted");
+
+    private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml";
+
+    private Document mDoc = null;
+
+    /** Logic for setting up tests (empty if not yet needed). */
+    public static void main(String[] params) throws Exception {}
+
+    @Before
+    public void setUp() throws Exception {
+        System.out.println("set up.");
+        mDoc = TestUtils.document();
+    }
+
+    /** Test for all fields valid. */
+    @Test
+    public void testAllFieldsValid() throws Exception {
+        System.out.println("starting testAllFieldsValid.");
+        testHrToOdSecurityLabels(ALL_FIELDS_VALID_FILE_NAME);
+    }
+
+    /** Tests missing optional fields passes. */
+    @Test
+    public void testMissingOptionalFields() throws Exception {
+        for (String optField : OPTIONAL_FIELD_NAMES) {
+            var ele =
+                    TestUtils.getElementsFromResource(
+                            Paths.get(SECURITY_LABELS_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
+            ele.get(0).removeAttribute(optField);
+            SecurityLabels securityLabels = new SecurityLabelsFactory().createFromHrElements(ele);
+            securityLabels.toOdDomElements(mDoc);
+        }
+    }
+
+    private void testHrToOdSecurityLabels(String fileName) throws Exception {
+        TestUtils.testHrToOd(
+                mDoc,
+                new SecurityLabelsFactory(),
+                SECURITY_LABELS_HR_PATH,
+                SECURITY_LABELS_OD_PATH,
+                fileName);
+    }
+}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java
new file mode 100644
index 0000000..ab8e85c
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 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.marshallable;
+
+import com.android.asllib.testutils.TestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.w3c.dom.Document;
+
+@RunWith(JUnit4.class)
+public class ThirdPartyVerificationTest {
+    private static final String THIRD_PARTY_VERIFICATION_HR_PATH =
+            "com/android/asllib/thirdpartyverification/hr";
+    private static final String THIRD_PARTY_VERIFICATION_OD_PATH =
+            "com/android/asllib/thirdpartyverification/od";
+
+    private static final String VALID_FILE_NAME = "valid.xml";
+    private static final String MISSING_URL_FILE_NAME = "missing-url.xml";
+
+    private Document mDoc = null;
+
+    /** Logic for setting up tests (empty if not yet needed). */
+    public static void main(String[] params) throws Exception {}
+
+    @Before
+    public void setUp() throws Exception {
+        System.out.println("set up.");
+        mDoc = TestUtils.document();
+    }
+
+    /** Test for valid. */
+    @Test
+    public void testValid() throws Exception {
+        System.out.println("starting testValid.");
+        testHrToOdThirdPartyVerification(VALID_FILE_NAME);
+    }
+
+    /** Tests missing url. */
+    @Test
+    public void testMissingUrl() throws Exception {
+        System.out.println("starting testMissingUrl.");
+        hrToOdExpectException(MISSING_URL_FILE_NAME);
+    }
+
+    private void hrToOdExpectException(String fileName) {
+        TestUtils.hrToOdExpectException(
+                new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_HR_PATH, fileName);
+    }
+
+    private void testHrToOdThirdPartyVerification(String fileName) throws Exception {
+        TestUtils.testHrToOd(
+                mDoc,
+                new ThirdPartyVerificationFactory(),
+                THIRD_PARTY_VERIFICATION_HR_PATH,
+                THIRD_PARTY_VERIFICATION_OD_PATH,
+                fileName);
+    }
+}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java
index faea340..6a29b86 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java
@@ -26,6 +26,8 @@
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
 import java.io.ByteArrayInputStream;
@@ -72,7 +74,7 @@
                             .findFirst()
                             .get()
                             .getTagName();
-            return XmlUtils.asElementList(root.getElementsByTagName(tagName));
+            return XmlUtils.getChildrenByTagName(root, tagName);
         } else {
             return List.of(root);
         }
@@ -105,7 +107,7 @@
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         factory.setNamespaceAware(true);
         Document document = factory.newDocumentBuilder().parse(stream);
-
+        stripEmptyElements(document);
         return docToStr(document, omitXmlDeclaration);
     }
 
@@ -125,6 +127,17 @@
                 });
     }
 
+    /** Helper for testing on-device to human-readable conversion expecting exception */
+    public static <T extends AslMarshallable> void odToHrExpectException(
+            AslMarshallableFactory<T> factory, String odFolderPath, String fileName) {
+        assertThrows(
+                MalformedXmlException.class,
+                () -> {
+                    factory.createFromOdElements(
+                            TestUtils.getElementsFromResource(Paths.get(odFolderPath, fileName)));
+                });
+    }
+
     /** Helper for testing human-readable to on-device conversion */
     public static <T extends AslMarshallable> void testHrToOd(
             Document doc,
@@ -133,20 +146,71 @@
             String odFolderPath,
             String fileName)
             throws Exception {
+        testFormatToFormat(doc, factory, hrFolderPath, odFolderPath, fileName, true);
+    }
+
+    /** Helper for testing on-device to human-readable conversion */
+    public static <T extends AslMarshallable> void testOdToHr(
+            Document doc,
+            AslMarshallableFactory<T> factory,
+            String odFolderPath,
+            String hrFolderPath,
+            String fileName)
+            throws Exception {
+        testFormatToFormat(doc, factory, odFolderPath, hrFolderPath, fileName, false);
+    }
+
+    /** Helper for testing format to format conversion */
+    private static <T extends AslMarshallable> void testFormatToFormat(
+            Document doc,
+            AslMarshallableFactory<T> factory,
+            String inFolderPath,
+            String outFolderPath,
+            String fileName,
+            boolean hrToOd)
+            throws Exception {
         AslMarshallable marshallable =
-                factory.createFromHrElements(
-                        TestUtils.getElementsFromResource(Paths.get(hrFolderPath, fileName)));
+                hrToOd
+                        ? factory.createFromHrElements(
+                                TestUtils.getElementsFromResource(
+                                        Paths.get(inFolderPath, fileName)))
+                        : factory.createFromOdElements(
+                                TestUtils.getElementsFromResource(
+                                        Paths.get(inFolderPath, fileName)));
 
-        for (var child : marshallable.toOdDomElements(doc)) {
-            doc.appendChild(child);
+        List<Element> elements =
+                hrToOd ? marshallable.toOdDomElements(doc) : marshallable.toHrDomElements(doc);
+        if (elements.isEmpty()) {
+            throw new IllegalStateException("elements was empty.");
+        } else if (elements.size() == 1) {
+            doc.appendChild(elements.get(0));
+        } else {
+            Element root = doc.createElement(TestUtils.HOLDER_TAG_NAME);
+            for (var child : elements) {
+                root.appendChild(child);
+            }
+            doc.appendChild(root);
         }
-        String converted = TestUtils.docToStr(doc, true);
-        System.out.println("converted: " + converted);
+        String converted = TestUtils.getFormattedXml(TestUtils.docToStr(doc, true), true);
+        System.out.println("Converted: " + converted);
+        String expectedOutContents =
+                TestUtils.getFormattedXml(
+                        TestUtils.readStrFromResource(Paths.get(outFolderPath, fileName)), true);
+        System.out.println("Expected: " + expectedOutContents);
+        assertEquals(expectedOutContents, converted);
+    }
 
-        String expectedOdContents =
-                TestUtils.readStrFromResource(Paths.get(odFolderPath, fileName));
-        assertEquals(
-                TestUtils.getFormattedXml(expectedOdContents, true),
-                TestUtils.getFormattedXml(converted, true));
+    private static void stripEmptyElements(Node node) {
+        NodeList children = node.getChildNodes();
+        for (int i = 0; i < children.getLength(); ++i) {
+            Node child = children.item(i);
+            if (child.getNodeType() == Node.TEXT_NODE) {
+                if (child.getTextContent().trim().length() == 0) {
+                    child.getParentNode().removeChild(child);
+                    i--;
+                }
+            }
+            stripEmptyElements(child);
+        }
     }
 }
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml
new file mode 100644
index 0000000..68e191e
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml
@@ -0,0 +1,17 @@
+<data-labels>
+    <data-shared dataCategory="actions_in_app"
+        dataType="user_interaction"
+        purposes="analytics" />
+    <data-shared dataCategory="actions_in_app"
+        dataType="in_app_search_history"
+        purposes="analytics" />
+    <data-shared dataCategory="actions_in_app"
+        dataType="installed_apps"
+        purposes="analytics" />
+    <data-shared dataCategory="actions_in_app"
+        dataType="user_generated_content"
+        purposes="analytics" />
+    <data-shared dataCategory="actions_in_app"
+        dataType="other"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml
new file mode 100644
index 0000000..a6bd17d
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml
@@ -0,0 +1,11 @@
+<data-labels>
+    <data-shared dataCategory="app_performance"
+        dataType="crash_logs"
+        purposes="analytics" />
+    <data-shared dataCategory="app_performance"
+        dataType="performance_diagnostics"
+        purposes="analytics" />
+    <data-shared dataCategory="app_performance"
+        dataType="other"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml
new file mode 100644
index 0000000..6274604
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml
@@ -0,0 +1,11 @@
+<data-labels>
+    <data-shared dataCategory="audio"
+        dataType="sound_recordings"
+        purposes="analytics" />
+    <data-shared dataCategory="audio"
+        dataType="music_files"
+        purposes="analytics" />
+    <data-shared dataCategory="audio"
+        dataType="other"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml
new file mode 100644
index 0000000..f7201f6
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="calendar"
+        dataType="calendar"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml
new file mode 100644
index 0000000..e8d40be
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="contacts"
+        dataType="contacts"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml
new file mode 100644
index 0000000..69e9b87
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml
@@ -0,0 +1,11 @@
+<data-labels>
+    <data-shared dataCategory="email_text_message"
+        dataType="emails"
+        purposes="analytics" />
+    <data-shared dataCategory="email_text_message"
+        dataType="text_messages"
+        purposes="analytics" />
+    <data-shared dataCategory="email_text_message"
+        dataType="other"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml
new file mode 100644
index 0000000..fdd8456
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml
@@ -0,0 +1,14 @@
+<data-labels>
+    <data-shared dataCategory="financial"
+        dataType="card_bank_account"
+        purposes="analytics" />
+    <data-shared dataCategory="financial"
+    dataType="purchase_history"
+    purposes="analytics" />
+    <data-shared dataCategory="financial"
+        dataType="credit_score"
+        purposes="analytics" />
+    <data-shared dataCategory="financial"
+        dataType="other"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml
new file mode 100644
index 0000000..bac58e6
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml
@@ -0,0 +1,8 @@
+<data-labels>
+    <data-shared dataCategory="health_fitness"
+        dataType="health"
+        purposes="analytics" />
+    <data-shared dataCategory="health_fitness"
+        dataType="fitness"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml
new file mode 100644
index 0000000..ee45f26
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="identifiers"
+        dataType="other"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml
new file mode 100644
index 0000000..e8e5911
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml
@@ -0,0 +1,8 @@
+<data-labels>
+    <data-shared dataCategory="location"
+        dataType="approx_location"
+        purposes="analytics" />
+    <data-shared dataCategory="location"
+        dataType="precise_location"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml
new file mode 100644
index 0000000..0b220f4
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="personal"
+    dataType="email_address"
+    purposes="" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml
new file mode 100644
index 0000000..ac221f2
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml
@@ -0,0 +1,4 @@
+<data-labels>
+    <data-shared dataCategory="personal"
+    dataType="email_address" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml
new file mode 100644
index 0000000..11b7368
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml
@@ -0,0 +1,8 @@
+<data-labels>
+    <data-shared dataCategory="personal"
+        dataType="name"
+        purposes="analytics|developer_communications" />
+    <data-shared dataCategory="personal"
+    dataType="email_address"
+    purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml
new file mode 100644
index 0000000..f1fbd56
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="personal"
+    dataType="unrecognized"
+    purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml
new file mode 100644
index 0000000..5907462
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml
@@ -0,0 +1,31 @@
+<data-labels>
+    <data-shared dataCategory="personal"
+        dataType="name"
+        ephemeral="true"
+        isSharingOptional="true"
+        purposes="analytics|developer_communications" />
+    <data-shared dataCategory="personal"
+    dataType="email_address"
+    purposes="analytics" />
+    <data-shared dataCategory="personal"
+    dataType="physical_address"
+    purposes="analytics" />
+    <data-shared dataCategory="personal"
+    dataType="phone_number"
+    purposes="analytics" />
+    <data-shared dataCategory="personal"
+    dataType="race_ethnicity"
+    purposes="analytics" />
+    <data-shared dataCategory="personal"
+    dataType="political_or_religious_beliefs"
+    purposes="analytics" />
+    <data-shared dataCategory="personal"
+    dataType="sexual_orientation_or_gender_identity"
+    purposes="analytics" />
+    <data-shared dataCategory="personal"
+    dataType="personal_identifiers"
+    purposes="analytics" />
+    <data-shared dataCategory="personal"
+    dataType="other"
+    purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml
new file mode 100644
index 0000000..05fe159
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml
@@ -0,0 +1,8 @@
+<data-labels>
+    <data-shared dataCategory="photo_video"
+        dataType="photos"
+        purposes="analytics" />
+    <data-shared dataCategory="photo_video"
+        dataType="videos"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml
new file mode 100644
index 0000000..a5de7be
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="search_and_browsing"
+        dataType="web_browsing_history"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml
new file mode 100644
index 0000000..f01e2df
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="storage"
+        dataType="files_docs"
+        purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml
new file mode 100644
index 0000000..f1fbd56
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="personal"
+    dataType="unrecognized"
+    purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml
new file mode 100644
index 0000000..c5be684
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml
@@ -0,0 +1,5 @@
+<data-labels>
+    <data-shared dataCategory="unrecognized"
+    dataType="email_address"
+    purposes="analytics" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml
new file mode 100644
index 0000000..161057a
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml
@@ -0,0 +1,11 @@
+<data-labels>
+    <data-accessed dataCategory="location"
+        dataType="approx_location"
+        purposes="app_functionality" />
+    <data-collected dataCategory="location"
+        dataType="precise_location"
+        purposes="app_functionality" />
+    <data-shared dataCategory="personal"
+        dataType="name"
+        purposes="app_functionality" />
+</data-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml
new file mode 100644
index 0000000..c5fef58
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml
@@ -0,0 +1,31 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="actions_in_app">
+            <pbundle_as_map name="user_interaction">
+                <int-array name="purposes" num="1">
+                    <item value="2" />
+                </int-array>
+            </pbundle_as_map>
+            <pbundle_as_map name="in_app_search_history">
+                <int-array name="purposes" num="1">
+                    <item value="2" />
+                </int-array>
+            </pbundle_as_map>
+            <pbundle_as_map name="installed_apps">
+                <int-array name="purposes" num="1">
+                    <item value="2" />
+                </int-array>
+            </pbundle_as_map>
+            <pbundle_as_map name="user_generated_content">
+                <int-array name="purposes" num="1">
+                    <item value="2" />
+                </int-array>
+            </pbundle_as_map>
+            <pbundle_as_map name="other">
+                <int-array name="purposes" num="1">
+                    <item value="2" />
+                </int-array>
+            </pbundle_as_map>
+        </pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml
new file mode 100644
index 0000000..4570145
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml
@@ -0,0 +1,21 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="app_performance">
+    <pbundle_as_map name="crash_logs">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="performance_diagnostics">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="other">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml
new file mode 100644
index 0000000..120f626
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml
@@ -0,0 +1,21 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="audio">
+    <pbundle_as_map name="sound_recordings">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="music_files">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="other">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml
new file mode 100644
index 0000000..59eb938
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="calendar">
+    <pbundle_as_map name="calendar">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml
new file mode 100644
index 0000000..f952bfb
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="contacts">
+    <pbundle_as_map name="contacts">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml
new file mode 100644
index 0000000..bcaa716
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml
@@ -0,0 +1,21 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="email_text_message">
+    <pbundle_as_map name="emails">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="text_messages">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="other">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml
new file mode 100644
index 0000000..a7bc82e
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml
@@ -0,0 +1,26 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="financial">
+    <pbundle_as_map name="card_bank_account">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="purchase_history">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="credit_score">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="other">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml
new file mode 100644
index 0000000..f3ab2bd9
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml
@@ -0,0 +1,16 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="health_fitness">
+    <pbundle_as_map name="health">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="fitness">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml
new file mode 100644
index 0000000..05c07e5
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="identifiers">
+    <pbundle_as_map name="other">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml
new file mode 100644
index 0000000..931d1ad
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml
@@ -0,0 +1,16 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="location">
+    <pbundle_as_map name="approx_location">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="precise_location">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml
new file mode 100644
index 0000000..83f4a67
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="personal">
+    <pbundle_as_map name="email_address">
+
+        <int-array name="purposes" num="2">
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml
new file mode 100644
index 0000000..532f5de
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml
@@ -0,0 +1,8 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="personal">
+    <pbundle_as_map name="email_address">
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml
new file mode 100644
index 0000000..14f9ef2
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml
@@ -0,0 +1,17 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="personal">
+    <pbundle_as_map name="name">
+        <int-array name="purposes" num="2">
+            <item value="2" />
+            <item value="3" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="email_address">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml
new file mode 100644
index 0000000..1c87de9
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml
@@ -0,0 +1,54 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="personal">
+    <pbundle_as_map name="name">
+        <int-array name="purposes" num="2">
+            <item value="2" />
+            <item value="3" />
+        </int-array>
+        <boolean name="is_sharing_optional" value="true" />
+        <boolean name="ephemeral" value="true" />
+    </pbundle_as_map>
+    <pbundle_as_map name="email_address">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="physical_address">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="phone_number">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="race_ethnicity">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="political_or_religious_beliefs">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="sexual_orientation_or_gender_identity">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="personal_identifiers">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="other">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml
new file mode 100644
index 0000000..a752b51
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml
@@ -0,0 +1,16 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="photo_video">
+    <pbundle_as_map name="photos">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+    <pbundle_as_map name="videos">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml
new file mode 100644
index 0000000..99bc188
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="search_and_browsing">
+    <pbundle_as_map name="web_browsing_history">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml
new file mode 100644
index 0000000..a4d2a62
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="storage">
+    <pbundle_as_map name="files_docs">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml
new file mode 100644
index 0000000..16195df
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="personal">
+    <pbundle_as_map name="unrecognized">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml
new file mode 100644
index 0000000..511940e
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml
@@ -0,0 +1,11 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="unrecognized">
+    <pbundle_as_map name="email_address">
+        <int-array name="purposes" num="1">
+            <item value="2" />
+        </int-array>
+    </pbundle_as_map>
+</pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml
new file mode 100644
index 0000000..f86dbc1
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml
@@ -0,0 +1,29 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_accessed">
+        <pbundle_as_map name="location">
+            <pbundle_as_map name="approx_location">
+                <int-array name="purposes" num="1">
+                    <item value="1"/>
+                </int-array>
+            </pbundle_as_map>
+        </pbundle_as_map>
+    </pbundle_as_map>
+    <pbundle_as_map name="data_collected">
+        <pbundle_as_map name="location">
+            <pbundle_as_map name="precise_location">
+                <int-array name="purposes" num="1">
+                    <item value="1"/>
+                </int-array>
+            </pbundle_as_map>
+        </pbundle_as_map>
+    </pbundle_as_map>
+    <pbundle_as_map name="data_shared">
+        <pbundle_as_map name="personal">
+            <pbundle_as_map name="name">
+                <int-array name="purposes" num="1">
+                    <item value="1"/>
+                </int-array>
+            </pbundle_as_map>
+        </pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml
new file mode 100644
index 0000000..54cc8e7
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml
@@ -0,0 +1,13 @@
+<pbundle_as_map name="data_labels">
+    <pbundle_as_map name="data_collected">
+        <pbundle_as_map name="location">
+            <pbundle_as_map name="approx_location">
+                <int-array name="purposes" num="1">
+                    <item value="1"/>
+                </int-array>
+                <boolean name="is_sharing_optional" value="false"/>
+                <boolean name="ephemeral" value="false"/>
+            </pbundle_as_map>
+        </pbundle_as_map>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml
index d1d4e33..3864f98 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml
@@ -1,5 +1,5 @@
 <pbundle_as_map name="data_labels">
-    <pbundle_as_map name="data_shared">
+<pbundle_as_map name="data_shared">
         <pbundle_as_map name="location">
             <pbundle_as_map name="approx_location">
                 <int-array name="purposes" num="1">
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml
new file mode 100644
index 0000000..940e48a
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml
@@ -0,0 +1,6 @@
+<safety-labels version="12345">
+    <security-labels
+        isDataDeletable="true"
+        isDataEncrypted="false"
+    />
+</safety-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml
new file mode 100644
index 0000000..bfbc5ae
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml
@@ -0,0 +1,4 @@
+<safety-labels version="12345">
+<third-party-verification url="www.example.com">
+    </third-party-verification>
+</safety-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml
new file mode 100644
index 0000000..b39c562b
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml
@@ -0,0 +1,7 @@
+<pbundle_as_map name="safety_labels">
+    <long name="version" value="12345"/>
+    <pbundle_as_map name="security_labels">
+        <boolean name="is_data_deletable" value="true" />
+        <boolean name="is_data_encrypted" value="false" />
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml
new file mode 100644
index 0000000..10653ff
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml
@@ -0,0 +1,6 @@
+<pbundle_as_map name="safety_labels">
+    <long name="version" value="12345"/>
+    <pbundle_as_map name="third_party_verification">
+        <string name="url" value="www.example.com"/>
+    </pbundle_as_map>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/hr/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/hr/all-fields-valid.xml
new file mode 100644
index 0000000..e2fb592
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/hr/all-fields-valid.xml
@@ -0,0 +1,4 @@
+<security-labels
+    isDataDeletable="true"
+    isDataEncrypted="false">
+</security-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/od/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/od/all-fields-valid.xml
new file mode 100644
index 0000000..7b2f656
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/securitylabels/od/all-fields-valid.xml
@@ -0,0 +1,4 @@
+<pbundle_as_map name="security_labels">
+    <boolean name="is_data_deletable" value="true" />
+    <boolean name="is_data_encrypted" value="false" />
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/missing-url.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/missing-url.xml
new file mode 100644
index 0000000..6738ac2
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/missing-url.xml
@@ -0,0 +1 @@
+<third-party-verification></third-party-verification>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/valid.xml
new file mode 100644
index 0000000..2a664f2
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/hr/valid.xml
@@ -0,0 +1 @@
+<third-party-verification url="www.example.com"></third-party-verification>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/valid.xml
new file mode 100644
index 0000000..dbeb592
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/valid.xml
@@ -0,0 +1,3 @@
+<pbundle_as_map name="third_party_verification">
+    <string name="url" value="www.example.com"/>
+</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
new file mode 100644
index 0000000..36beb93
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
@@ -0,0 +1,35 @@
+<app-metadata-bundles version="123">
+    <system-app-safety-label url="www.example.com">
+    </system-app-safety-label>
+    <safety-labels version="12345">
+        <data-labels>
+            <data-shared dataCategory="location"
+                dataType="approx_location"
+                isSharingOptional="false"
+                ephemeral="false"
+                purposes="app_functionality" />
+            <data-shared dataCategory="location"
+                dataType="precise_location"
+                isSharingOptional="true"
+                ephemeral="true"
+                purposes="app_functionality|analytics" />
+        </data-labels>
+        <security-labels
+            isDataDeletable="true"
+            isDataEncrypted="false"
+        />
+        <third-party-verification url="www.example.com">
+        </third-party-verification>
+    </safety-labels>
+    <transparency-info>
+        <developer-info
+            name="max"
+            email="max@example.com"
+            address="111 blah lane"
+            countryRegion="US"
+            relationship="aosp"
+            website="example.com"
+            appDeveloperRegistryId="registry_id" />
+        <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" />
+    </transparency-info>
+</app-metadata-bundles>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
new file mode 100644
index 0000000..db21280
--- /dev/null
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
@@ -0,0 +1,70 @@
+<bundle>
+    <long name="version" value="123"/>
+    <pbundle_as_map name="safety_labels">
+        <long name="version" value="12345"/>
+        <pbundle_as_map name="data_labels">
+            <pbundle_as_map name="data_shared">
+                <pbundle_as_map name="location">
+                    <pbundle_as_map name="approx_location">
+                        <int-array name="purposes" num="1">
+                            <item value="1"/>
+                        </int-array>
+                        <boolean name="is_sharing_optional" value="false"/>
+                        <boolean name="ephemeral" value="false"/>
+                    </pbundle_as_map>
+                    <pbundle_as_map name="precise_location">
+                        <int-array name="purposes" num="2">
+                            <item value="1"/>
+                            <item value="2"/>
+                        </int-array>
+                        <boolean name="is_sharing_optional" value="true"/>
+                        <boolean name="ephemeral" value="true"/>
+                    </pbundle_as_map>
+                </pbundle_as_map>
+            </pbundle_as_map>
+        </pbundle_as_map>
+        <pbundle_as_map name="security_labels">
+            <boolean name="is_data_deletable" value="true"/>
+            <boolean name="is_data_encrypted" value="false"/>
+        </pbundle_as_map>
+        <pbundle_as_map name="third_party_verification">
+            <string name="url" value="www.example.com"/>
+        </pbundle_as_map>
+    </pbundle_as_map>
+    <pbundle_as_map name="system_app_safety_label">
+        <string name="url" value="www.example.com"/>
+    </pbundle_as_map>
+    <pbundle_as_map name="transparency_info">
+        <pbundle_as_map name="developer_info">
+            <string name="name" value="max"/>
+            <string name="email" value="max@example.com"/>
+            <string name="address" value="111 blah lane"/>
+            <string name="country_region" value="US"/>
+            <long name="relationship" value="5"/>
+            <string name="website" value="example.com"/>
+        </pbundle_as_map>
+        <pbundle_as_map name="app_info">
+            <string name="title" value="beervision"/>
+            <string name="description" value="a beer app"/>
+            <boolean name="contains_ads" value="true"/>
+            <boolean name="obey_aps" value="false"/>
+            <boolean name="ads_fingerprinting" value="false"/>
+            <boolean name="security_fingerprinting" value="false"/>
+            <string name="privacy_policy" value="www.example.com"/>
+            <string-array name="security_endpoint" num="3">
+                <item value="url1"/>
+                <item value="url2"/>
+                <item value="url3"/>
+            </string-array>
+            <string-array name="first_party_endpoint" num="1">
+                <item value="url1"/>
+            </string-array>
+            <string-array name="service_provider_endpoint" num="2">
+                <item value="url55"/>
+                <item value="url56"/>
+            </string-array>
+            <string name="category" value="Food and drink"/>
+            <string name="email" value="max@maxloh.com"/>
+        </pbundle_as_map>
+    </pbundle_as_map>
+</bundle>
\ No newline at end of file
diff --git a/wifi/wifi.aconfig b/wifi/wifi.aconfig
index 3c734bc..6c4e4c3 100644
--- a/wifi/wifi.aconfig
+++ b/wifi/wifi.aconfig
@@ -1,5 +1,4 @@
 package: "android.net.wifi.flags"
-container: "system"
 
 flag {
     name: "get_device_cross_akm_roaming_support"